From cf97f21d356c9a22d356b5ea2add7a1961bc844d Mon Sep 17 00:00:00 2001 From: hiroshi Date: Wed, 3 Aug 2016 23:32:19 +0800 Subject: [PATCH 001/521] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=98=85=E8=AF=BB?= =?UTF-8?q?=E5=99=A8=E4=BD=BF=E7=94=A8=E6=96=B9=E5=BC=8F=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E6=81=A2=E5=A4=8D=E4=B8=8A=E4=B8=80=E6=AC=A1=E9=98=85?= =?UTF-8?q?=E8=AF=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 4 +- .../com/hiroshi/cimoc/CimocApplication.java | 1 - .../com/hiroshi/cimoc/core/ComicManager.java | 8 + .../cimoc/presenter/ReaderPresenter.java | 26 +- .../cimoc/ui/activity/ReaderActivity.java | 27 +- .../cimoc/ui/adapter/PicturePagerAdapter.java | 27 +- .../photo/OnScaleDragGestureListener.java | 29 + .../ui/custom/photo/PhotoDraweeView.java | 71 +++ .../photo/PhotoDraweeViewController.java | 496 +++++++++++++++ .../ui/custom/photo/ScaleDragDetector.java | 197 ++++++ .../AbstractAnimatedZoomableController.java | 187 ------ .../zoomable/AnimatedZoomableController.java | 107 ---- .../AnimatedZoomableControllerSupport.java | 101 --- .../zoomable/DefaultZoomableController.java | 579 ------------------ .../zoomable/GestureListenerWrapper.java | 77 --- .../zoomable/MultiPointerGestureDetector.java | 271 -------- .../zoomable/TransformGestureDetector.java | 176 ------ .../custom/zoomable/ZoomableController.java | 110 ---- .../custom/zoomable/ZoomableDraweeView.java | 335 ---------- .../zoomable/ZoomableDraweeViewSupport.java | 53 -- .../java/com/hiroshi/cimoc/utils/ExLog.java | 8 +- app/src/main/res/layout/item_picture.xml | 2 +- 22 files changed, 861 insertions(+), 2031 deletions(-) create mode 100644 app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/OnScaleDragGestureListener.java create mode 100644 app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/PhotoDraweeView.java create mode 100644 app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/PhotoDraweeViewController.java create mode 100644 app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/ScaleDragDetector.java delete mode 100644 app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/AbstractAnimatedZoomableController.java delete mode 100644 app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/AnimatedZoomableController.java delete mode 100644 app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/AnimatedZoomableControllerSupport.java delete mode 100644 app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/DefaultZoomableController.java delete mode 100644 app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/GestureListenerWrapper.java delete mode 100644 app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/MultiPointerGestureDetector.java delete mode 100644 app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/TransformGestureDetector.java delete mode 100644 app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/ZoomableController.java delete mode 100644 app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/ZoomableDraweeView.java delete mode 100644 app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/ZoomableDraweeViewSupport.java diff --git a/app/build.gradle b/app/build.gradle index 54acdedf..198ced10 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -38,8 +38,8 @@ dependencies { compile 'org.greenrobot:eventbus:3.0.0' compile 'org.greenrobot:greendao:3.0.1' compile 'com.squareup.okhttp3:okhttp:3.4.1' - compile 'com.facebook.fresco:fresco:0.11.0' - compile 'com.facebook.fresco:imagepipeline-okhttp3:0.11.0' + compile 'com.facebook.fresco:fresco:0.12.0' + compile 'com.facebook.fresco:imagepipeline-okhttp3:0.12.0' compile 'org.jsoup:jsoup:1.9.2' compile 'org.adw.library:discrete-seekbar:1.0.1' } diff --git a/app/src/main/java/com/hiroshi/cimoc/CimocApplication.java b/app/src/main/java/com/hiroshi/cimoc/CimocApplication.java index 9a47f7d5..9d1659a7 100644 --- a/app/src/main/java/com/hiroshi/cimoc/CimocApplication.java +++ b/app/src/main/java/com/hiroshi/cimoc/CimocApplication.java @@ -32,7 +32,6 @@ public void onCreate() { initDatabase(); preferences = getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE); Fresco.initialize(this); -// ExLog.enable(); } private void initDatabase() { diff --git a/app/src/main/java/com/hiroshi/cimoc/core/ComicManager.java b/app/src/main/java/com/hiroshi/cimoc/core/ComicManager.java index 02b79e13..ee6bcab1 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/ComicManager.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/ComicManager.java @@ -213,6 +213,14 @@ public String getLast() { return comic.getLast(); } + public int getPage() { + Integer page = comic.getPage(); + if (page == null) { + return -1; + } + return page; + } + public void saveComic() { if (isComicExist()) { ExLog.d("ComicManager", "save" + " [" + comic.getId() + "] " + comic.getTitle()); diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/ReaderPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/ReaderPresenter.java index 9a6538d9..6d3dbe6d 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/ReaderPresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/ReaderPresenter.java @@ -80,22 +80,24 @@ public void onPageSelected(int position) { if (chapter == null) { mReaderActivity.hideChapterInfo(); } else if (flag) { - switchChapter(); + switchChapter(mPreloadAdapter.getValidProgress()); } else { mReaderActivity.setReadProgress(mPreloadAdapter.getValidProgress()); } } - public int getSource() { - return mComicManager.getSource(); + public void onProgressChanged(int value, boolean fromUser) { + if (fromUser) { + mReaderActivity.setCurrentItem(mPreloadAdapter.getCurrentOffset() + value - 1); + } } - public int getOffset() { - return mPreloadAdapter.getCurrentOffset(); + public int getSource() { + return mComicManager.getSource(); } - private void switchChapter() { - mReaderActivity.updateChapterInfo(mPreloadAdapter.getValidProgress(), mPreloadAdapter.getMax(), mPreloadAdapter.getValidChapter().getTitle()); + private void switchChapter(int page) { + mReaderActivity.updateChapterInfo(page, mPreloadAdapter.getMax(), mPreloadAdapter.getValidChapter().getTitle()); mComicManager.setLast(mPreloadAdapter.getValidChapter().getPath()); } @@ -112,9 +114,15 @@ public void onEvent(EventMessage msg) { mReaderActivity.setNextImage(array); mPreloadAdapter.moveNext(array.length); } - switchChapter(); - mReaderActivity.setNoneLimit(); + int page = mComicManager.getPage(); + if (!load && mComicManager.getLast().equals(mPreloadAdapter.getValidChapter().getPath()) && page != -1) { + switchChapter(page); + mReaderActivity.setCurrentItem(mPreloadAdapter.getCurrentOffset() + page - 1); + } else { + switchChapter(mPreloadAdapter.getValidProgress()); + } load = true; + mReaderActivity.setNoneLimit(); status = LOAD_NULL; break; case EventMessage.PARSE_PIC_FAIL: diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java index 692321f7..8d75b437 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java @@ -2,9 +2,8 @@ import android.content.Context; import android.content.Intent; +import android.graphics.Point; import android.support.v4.view.ViewPager; -import android.view.GestureDetector; -import android.view.MotionEvent; import android.view.View; import android.widget.LinearLayout; import android.widget.TextView; @@ -14,6 +13,7 @@ import com.hiroshi.cimoc.presenter.ReaderPresenter; import com.hiroshi.cimoc.ui.adapter.PicturePagerAdapter; import com.hiroshi.cimoc.ui.custom.LimitedViewPager; +import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeViewController; import com.hiroshi.cimoc.utils.ControllerBuilderFactory; import org.adw.library.widgets.discreteseekbar.DiscreteSeekBar; @@ -47,12 +47,17 @@ public void onBackPressed() { @Override protected void initView() { mPagerAdapter = new PicturePagerAdapter(new LinkedList(), getLayoutInflater(), - new GestureDetector.SimpleOnGestureListener() { + new PhotoDraweeViewController.OnSingleTapListener() { @Override - public boolean onDoubleTap(MotionEvent e) { - int visibility = mToolLayout.isShown() ? View.GONE : View.VISIBLE; - mToolLayout.setVisibility(visibility); - return true; + public void onSingleTap(View view, float x, float y) { + Point point = new Point(); + getWindowManager().getDefaultDisplay().getSize(point); + float limitX = point.x / 3.0f; + float limitY = point.y / 3.0f; + if (limitX <= x && x <= 2 * limitX && limitY <= y && y <= 2 * limitY) { + int visibility = mToolLayout.isShown() ? View.GONE : View.VISIBLE; + mToolLayout.setVisibility(visibility); + } } }, ControllerBuilderFactory.getControllerBuilder(mPresenter.getSource(), this)); mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @@ -81,9 +86,7 @@ public void onPageScrollStateChanged(int state) { mSeekBar.setOnProgressChangeListener(new DiscreteSeekBar.OnProgressChangeListener() { @Override public void onProgressChanged(DiscreteSeekBar seekBar, int value, boolean fromUser) { - if (fromUser) { - mViewPager.setCurrentItem(mPresenter.getOffset() + value - 1, false); - } + mPresenter.onProgressChanged(value, fromUser); } @Override @@ -140,6 +143,10 @@ public void hideChapterInfo() { mChapterTitle.setText(null); } + public void setCurrentItem(int item) { + mViewPager.setCurrentItem(item, false); + } + public void updateChapterInfo(int progress, int max, String title) { mSeekBar.setMax(max); mSeekBar.setProgress(progress); diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePagerAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePagerAdapter.java index 9ef2ee21..7f982ad9 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePagerAdapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePagerAdapter.java @@ -1,5 +1,6 @@ package com.hiroshi.cimoc.ui.adapter; +import android.graphics.drawable.Animatable; import android.support.v4.view.PagerAdapter; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.LayoutInflater; @@ -8,9 +9,13 @@ import android.widget.TextView; import com.facebook.drawee.backends.pipeline.PipelineDraweeControllerBuilder; +import com.facebook.drawee.controller.BaseControllerListener; +import com.facebook.imagepipeline.image.ImageInfo; import com.hiroshi.cimoc.R; import com.hiroshi.cimoc.ui.custom.LimitedViewPager; -import com.hiroshi.cimoc.ui.custom.zoomable.ZoomableDraweeView; +import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeView; +import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeViewController; +import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeViewController.OnSingleTapListener; import java.util.Arrays; import java.util.List; @@ -28,14 +33,14 @@ public class PicturePagerAdapter extends PagerAdapter { private List images; private LayoutInflater inflater; - private SimpleOnGestureListener listener; + private OnSingleTapListener listener; private PipelineDraweeControllerBuilder builder; private int prev; private int next; private int pStatus; private int nStatus; - public PicturePagerAdapter(List images, LayoutInflater inflater, SimpleOnGestureListener listener, + public PicturePagerAdapter(List images, LayoutInflater inflater, OnSingleTapListener listener, PipelineDraweeControllerBuilder builder) { this.images = images; this.inflater = inflater; @@ -125,9 +130,19 @@ public Object instantiateItem(ViewGroup container, int position) { child.setTag(POSITION_NONE); } else { child = inflater.inflate(R.layout.item_picture, container, false); - ZoomableDraweeView draweeView = (ZoomableDraweeView) child.findViewById(R.id.picture_image_view); - draweeView.setController(builder.setUri(images.get(position - prev - 1)).setTapToRetryEnabled(true).build()); - draweeView.setTapListener(listener); + final PhotoDraweeView draweeView = (PhotoDraweeView) child.findViewById(R.id.picture_image_view); + draweeView.setOnSingleTapListener(listener); + builder.setControllerListener(new BaseControllerListener() { + @Override + public void onFinalImageSet(String id, ImageInfo imageInfo, Animatable animatable) { + super.onFinalImageSet(id, imageInfo, animatable); + if (imageInfo == null || draweeView == null) { + return; + } + draweeView.update(imageInfo.getWidth(), imageInfo.getHeight()); + } + }).setTapToRetryEnabled(true); + draweeView.setController(builder.setUri(images.get(position - prev - 1)).build()); child.setTag(POSITION_UNCHANGED); } container.addView(child); diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/OnScaleDragGestureListener.java b/app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/OnScaleDragGestureListener.java new file mode 100644 index 00000000..de32f063 --- /dev/null +++ b/app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/OnScaleDragGestureListener.java @@ -0,0 +1,29 @@ +package com.hiroshi.cimoc.ui.custom.photo; + +/** + * **************************************************************************** + * Copyright 2011, 2012 Chris Banes. + * + * 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. + * ***************************************************************************** + */ + +public interface OnScaleDragGestureListener { + void onDrag(float dx, float dy); + + void onFling(float startX, float startY, float velocityX, float velocityY); + + void onScale(float scaleFactor, float focusX, float focusY); + + void onScaleEnd(); +} diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/PhotoDraweeView.java b/app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/PhotoDraweeView.java new file mode 100644 index 00000000..9f2bd959 --- /dev/null +++ b/app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/PhotoDraweeView.java @@ -0,0 +1,71 @@ +package com.hiroshi.cimoc.ui.custom.photo; + +import android.content.Context; +import android.graphics.Canvas; +import android.support.annotation.NonNull; +import android.util.AttributeSet; +import android.view.MotionEvent; + +import com.facebook.drawee.generic.GenericDraweeHierarchy; +import com.facebook.drawee.view.SimpleDraweeView; + +public class PhotoDraweeView extends SimpleDraweeView { + + private PhotoDraweeViewController mPhotoDraweeViewController; + + public PhotoDraweeView(Context context, GenericDraweeHierarchy hierarchy) { + super(context, hierarchy); + init(); + } + + public PhotoDraweeView(Context context) { + super(context); + init(); + } + + public PhotoDraweeView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public PhotoDraweeView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + protected void init() { + if (mPhotoDraweeViewController == null || mPhotoDraweeViewController.getDraweeView() == null) { + mPhotoDraweeViewController = new PhotoDraweeViewController(this); + } + } + + @Override public boolean onTouchEvent(MotionEvent event) { + return super.onTouchEvent(event); + } + + @Override protected void onDraw(@NonNull Canvas canvas) { + int saveCount = canvas.save(); + canvas.concat(mPhotoDraweeViewController.getDrawMatrix()); + super.onDraw(canvas); + canvas.restoreToCount(saveCount); + } + + @Override protected void onAttachedToWindow() { + init(); + super.onAttachedToWindow(); + } + + @Override protected void onDetachedFromWindow() { + mPhotoDraweeViewController.onDetachedFromWindow(); + super.onDetachedFromWindow(); + } + + public void setOnSingleTapListener(PhotoDraweeViewController.OnSingleTapListener listener) { + mPhotoDraweeViewController.setOnSingleTapListener(listener); + } + + public void update(int imageInfoWidth, int imageInfoHeight) { + mPhotoDraweeViewController.update(imageInfoWidth, imageInfoHeight); + } + +} diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/PhotoDraweeViewController.java b/app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/PhotoDraweeViewController.java new file mode 100644 index 00000000..d7dc6e9c --- /dev/null +++ b/app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/PhotoDraweeViewController.java @@ -0,0 +1,496 @@ +package com.hiroshi.cimoc.ui.custom.photo; + +import android.content.Context; +import android.graphics.Matrix; +import android.graphics.RectF; +import android.os.Build; +import android.support.annotation.Nullable; +import android.support.v4.view.GestureDetectorCompat; +import android.support.v4.view.MotionEventCompat; +import android.support.v4.widget.ScrollerCompat; +import android.view.GestureDetector; +import android.view.GestureDetector.OnDoubleTapListener; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnTouchListener; +import android.view.ViewParent; +import android.view.animation.AccelerateDecelerateInterpolator; +import android.view.animation.Interpolator; + +import com.facebook.drawee.drawable.ScalingUtils; +import com.facebook.drawee.generic.GenericDraweeHierarchy; +import com.facebook.drawee.view.DraweeView; + +import java.lang.ref.WeakReference; + +public class PhotoDraweeViewController implements OnTouchListener, OnScaleDragGestureListener, OnDoubleTapListener { + + public static final float MIN_SCALE = 1.0f; + public static final float MID_SCALE = 2.0f; + public static final float MAX_SCALE = 3.0f; + + public interface OnSingleTapListener { + void onSingleTap(View view, float x, float y); + } + + public interface OnScaleChangeListener { + void onScaleChange(float scaleFactor, float focusX, float focusY); + } + + private static final int EDGE_NONE = -1; + private static final int EDGE_LEFT = 0; + private static final int EDGE_RIGHT = 1; + private static final int EDGE_BOTH = 2; + + private final float[] mMatrixValues = new float[9]; + private final RectF mDisplayRect = new RectF(); + private final Interpolator mZoomInterpolator = new AccelerateDecelerateInterpolator(); + + private long mZoomDuration = 200L; + + private ScaleDragDetector mScaleDragDetector; + private GestureDetectorCompat mGestureDetector; + + private boolean mBlockParentIntercept = false; + private boolean mAllowParentInterceptOnEdge = true; + private int mScrollEdge = EDGE_BOTH; + + private final Matrix mMatrix = new Matrix(); + private int mImageInfoHeight = -1, mImageInfoWidth = -1; + private FlingRunnable mCurrentFlingRunnable; + private WeakReference> mDraweeView; + + private OnSingleTapListener mSingleTapListener; + private OnScaleChangeListener mScaleChangeListener; + + public PhotoDraweeViewController(DraweeView draweeView) { + mDraweeView = new WeakReference<>(draweeView); + draweeView.getHierarchy().setActualImageScaleType(ScalingUtils.ScaleType.FIT_CENTER); + draweeView.setOnTouchListener(this); + mScaleDragDetector = new ScaleDragDetector(draweeView.getContext(), this); + mGestureDetector = new GestureDetectorCompat(draweeView.getContext(), new GestureDetector.SimpleOnGestureListener()); + mGestureDetector.setOnDoubleTapListener(this); + } + + @Nullable public DraweeView getDraweeView() { + return mDraweeView.get(); + } + + public float getScale() { + return (float) Math.sqrt( + (float) Math.pow(getMatrixValue(mMatrix, Matrix.MSCALE_X), 2) + (float) Math.pow( + getMatrixValue(mMatrix, Matrix.MSKEW_Y), 2)); + } + + private void setScale(float scale, float focalX, float focalY, boolean animate) { + DraweeView draweeView = getDraweeView(); + + if (draweeView == null || scale < MIN_SCALE || scale > MAX_SCALE) { + return; + } + + if (animate) { + draweeView.post(new AnimatedZoomRunnable(getScale(), scale, focalX, focalY)); + } else { + mMatrix.setScale(scale, scale, focalX, focalY); + checkMatrixAndInvalidate(); + } + } + + public void setZoomTransitionDuration(long duration) { + duration = duration < 0 ? mZoomDuration : duration; + mZoomDuration = duration; + } + + public void setAllowParentInterceptOnEdge(boolean allow) { + mAllowParentInterceptOnEdge = allow; + } + + public void setOnScaleChangeListener(OnScaleChangeListener listener) { + mScaleChangeListener = listener; + } + + public void setOnSingleTapListener(OnSingleTapListener listener) { + mSingleTapListener = listener; + } + + public OnSingleTapListener getOnSingleTapListener() { + return mSingleTapListener; + } + + public void update(int imageInfoWidth, int imageInfoHeight) { + mImageInfoWidth = imageInfoWidth; + mImageInfoHeight = imageInfoHeight; + updateBaseMatrix(); + } + + private int getViewWidth() { + DraweeView draweeView = getDraweeView(); + if (draweeView != null) { + return draweeView.getWidth() + - draweeView.getPaddingLeft() + - draweeView.getPaddingRight(); + } + return 0; + } + + private int getViewHeight() { + DraweeView draweeView = getDraweeView(); + if (draweeView != null) { + return draweeView.getHeight() + - draweeView.getPaddingTop() + - draweeView.getPaddingBottom(); + } + return 0; + } + + private float getMatrixValue(Matrix matrix, int whichValue) { + matrix.getValues(mMatrixValues); + return mMatrixValues[whichValue]; + } + + public Matrix getDrawMatrix() { + return mMatrix; + } + + public RectF getDisplayRect() { + checkMatrixBounds(); + return getDisplayRect(getDrawMatrix()); + } + + public void checkMatrixAndInvalidate() { + DraweeView draweeView = getDraweeView(); + if (draweeView == null) { + return; + } + if (checkMatrixBounds()) { + draweeView.invalidate(); + } + } + + public boolean checkMatrixBounds() { + RectF rect = getDisplayRect(getDrawMatrix()); + if (rect == null) { + return false; + } + + float height = rect.height(); + float width = rect.width(); + float deltaX = 0.0F; + float deltaY = 0.0F; + int viewHeight = getViewHeight(); + + if (height <= (float) viewHeight) { + deltaY = (viewHeight - height) / 2 - rect.top; + } else if (rect.top > 0.0F) { + deltaY = -rect.top; + } else if (rect.bottom < (float) viewHeight) { + deltaY = viewHeight - rect.bottom; + } + int viewWidth = getViewWidth(); + if (width <= viewWidth) { + deltaX = (viewWidth - width) / 2 - rect.left; + mScrollEdge = EDGE_BOTH; + } else if (rect.left > 0) { + deltaX = -rect.left; + mScrollEdge = EDGE_LEFT; + } else if (rect.right < viewWidth) { + deltaX = viewWidth - rect.right; + mScrollEdge = EDGE_RIGHT; + } else { + mScrollEdge = EDGE_NONE; + } + + mMatrix.postTranslate(deltaX, deltaY); + return true; + } + + private RectF getDisplayRect(Matrix matrix) { + DraweeView draweeView = getDraweeView(); + if (draweeView == null || (mImageInfoWidth == -1 && mImageInfoHeight == -1)) { + return null; + } + mDisplayRect.set(0.0F, 0.0F, mImageInfoWidth, mImageInfoHeight); + draweeView.getHierarchy().getActualImageBounds(mDisplayRect); + matrix.mapRect(mDisplayRect); + return mDisplayRect; + } + + private void updateBaseMatrix() { + if (mImageInfoWidth == -1 && mImageInfoHeight == -1) { + return; + } + resetMatrix(); + } + + private void resetMatrix() { + mMatrix.reset(); + checkMatrixBounds(); + DraweeView draweeView = getDraweeView(); + if (draweeView != null) { + draweeView.invalidate(); + } + } + + private void checkMinScale() { + DraweeView draweeView = getDraweeView(); + if (draweeView == null) { + return; + } + + if (getScale() < MIN_SCALE) { + RectF rect = getDisplayRect(); + if (null != rect) { + draweeView.post(new AnimatedZoomRunnable(getScale(), MIN_SCALE, rect.centerX(), + rect.centerY())); + } + } + } + + @Override public boolean onSingleTapConfirmed(MotionEvent e) { + DraweeView draweeView = mDraweeView.get(); + if (draweeView == null) { + return false; + } + if (mSingleTapListener != null) { + mSingleTapListener.onSingleTap(draweeView, e.getX(), e.getY()); + return true; + } + return false; + } + + @Override public boolean onDoubleTap(MotionEvent event) { + try { + float scale = getScale(); + float x = event.getX(); + float y = event.getY(); + + if (scale < MID_SCALE) { + setScale(MID_SCALE, x, y, true); + } else { + setScale(MIN_SCALE, x, y, true); + } + } catch (Exception e) { + // Can sometimes happen when getX() and getY() is called + } + return true; + } + + @Override public boolean onDoubleTapEvent(MotionEvent event) { + return false; + } + + @Override public void onScale(float scaleFactor, float focusX, float focusY) { + if (getScale() < MAX_SCALE || scaleFactor < 1.0F) { + + if (mScaleChangeListener != null) { + mScaleChangeListener.onScaleChange(scaleFactor, focusX, focusY); + } + + mMatrix.postScale(scaleFactor, scaleFactor, focusX, focusY); + checkMatrixAndInvalidate(); + } + } + + @Override public void onScaleEnd() { + checkMinScale(); + } + + @Override public void onDrag(float dx, float dy) { + DraweeView draweeView = getDraweeView(); + + if (draweeView != null && !mScaleDragDetector.isScaling()) { + mMatrix.postTranslate(dx, dy); + checkMatrixAndInvalidate(); + + ViewParent parent = draweeView.getParent(); + if (parent == null) { + return; + } + + if (mAllowParentInterceptOnEdge + && !mScaleDragDetector.isScaling() + && !mBlockParentIntercept) { + if (mScrollEdge == EDGE_BOTH || (mScrollEdge == EDGE_LEFT && dx >= 1f) || ( + mScrollEdge == EDGE_RIGHT + && dx <= -1f)) { + parent.requestDisallowInterceptTouchEvent(false); + } + } else { + parent.requestDisallowInterceptTouchEvent(true); + } + } + } + + @Override public void onFling(float startX, float startY, float velocityX, float velocityY) { + DraweeView draweeView = getDraweeView(); + if (draweeView == null) { + return; + } + mCurrentFlingRunnable = new FlingRunnable(draweeView.getContext()); + mCurrentFlingRunnable.fling(getViewWidth(), getViewHeight(), (int) velocityX, + (int) velocityY); + draweeView.post(mCurrentFlingRunnable); + } + + @Override public boolean onTouch(View v, MotionEvent event) { + int action = MotionEventCompat.getActionMasked(event); + switch (action) { + case MotionEvent.ACTION_DOWN: { + ViewParent parent = v.getParent(); + if (parent != null) { + parent.requestDisallowInterceptTouchEvent(true); + } + cancelFling(); + } + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: { + ViewParent parent = v.getParent(); + if (parent != null) { + parent.requestDisallowInterceptTouchEvent(false); + } + } + break; + } + + boolean wasScaling = mScaleDragDetector.isScaling(); + boolean wasDragging = mScaleDragDetector.isDragging(); + + boolean handled = mScaleDragDetector.onTouchEvent(event); + + boolean noScale = !wasScaling && !mScaleDragDetector.isScaling(); + boolean noDrag = !wasDragging && !mScaleDragDetector.isDragging(); + mBlockParentIntercept = noScale && noDrag; + + if (mGestureDetector.onTouchEvent(event)) { + handled = true; + } + + return handled; + } + + private class AnimatedZoomRunnable implements Runnable { + private final float mFocalX, mFocalY; + private final long mStartTime; + private final float mZoomStart, mZoomEnd; + + public AnimatedZoomRunnable(final float currentZoom, final float targetZoom, + final float focalX, final float focalY) { + mFocalX = focalX; + mFocalY = focalY; + mStartTime = System.currentTimeMillis(); + mZoomStart = currentZoom; + mZoomEnd = targetZoom; + } + + @Override public void run() { + + DraweeView draweeView = getDraweeView(); + if (draweeView == null) { + return; + } + + float t = interpolate(); + float scale = mZoomStart + t * (mZoomEnd - mZoomStart); + float deltaScale = scale / getScale(); + + onScale(deltaScale, mFocalX, mFocalY); + + if (t < 1f) { + postOnAnimation(draweeView, this); + } + } + + private float interpolate() { + float t = 1f * (System.currentTimeMillis() - mStartTime) / mZoomDuration; + t = Math.min(1f, t); + t = mZoomInterpolator.getInterpolation(t); + return t; + } + } + + private class FlingRunnable implements Runnable { + + private final ScrollerCompat mScroller; + private int mCurrentX, mCurrentY; + + public FlingRunnable(Context context) { + mScroller = ScrollerCompat.create(context); + } + + public void cancelFling() { + mScroller.abortAnimation(); + } + + public void fling(int viewWidth, int viewHeight, int velocityX, int velocityY) { + final RectF rect = getDisplayRect(); + if (null == rect) { + return; + } + + final int startX = Math.round(-rect.left); + final int minX, maxX, minY, maxY; + + if (viewWidth < rect.width()) { + minX = 0; + maxX = Math.round(rect.width() - viewWidth); + } else { + minX = maxX = startX; + } + + final int startY = Math.round(-rect.top); + if (viewHeight < rect.height()) { + minY = 0; + maxY = Math.round(rect.height() - viewHeight); + } else { + minY = maxY = startY; + } + + mCurrentX = startX; + mCurrentY = startY; + + if (startX != maxX || startY != maxY) { + mScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY, 0, 0); + } + } + + @Override public void run() { + if (mScroller.isFinished()) { + return; + } + + DraweeView draweeView = getDraweeView(); + + if (draweeView != null && mScroller.computeScrollOffset()) { + final int newX = mScroller.getCurrX(); + final int newY = mScroller.getCurrY(); + mMatrix.postTranslate(mCurrentX - newX, mCurrentY - newY); + draweeView.invalidate(); + mCurrentX = newX; + mCurrentY = newY; + postOnAnimation(draweeView, this); + } + } + } + + private void cancelFling() { + if (mCurrentFlingRunnable != null) { + mCurrentFlingRunnable.cancelFling(); + mCurrentFlingRunnable = null; + } + } + + private void postOnAnimation(View view, Runnable runnable) { + if (Build.VERSION.SDK_INT >= 16) { + view.postOnAnimation(runnable); + } else { + view.postDelayed(runnable, 16L); + } + } + + protected void onDetachedFromWindow() { + cancelFling(); + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/ScaleDragDetector.java b/app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/ScaleDragDetector.java new file mode 100644 index 00000000..11374974 --- /dev/null +++ b/app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/ScaleDragDetector.java @@ -0,0 +1,197 @@ +package com.hiroshi.cimoc.ui.custom.photo; + +import android.content.Context; +import android.support.v4.view.MotionEventCompat; +import android.view.MotionEvent; +import android.view.ScaleGestureDetector; +import android.view.VelocityTracker; +import android.view.ViewConfiguration; + +/** + * **************************************************************************** + * Copyright 2011, 2012 Chris Banes. + * + * 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. + * ***************************************************************************** + */ +public class ScaleDragDetector implements ScaleGestureDetector.OnScaleGestureListener { + + private static final int INVALID_POINTER_ID = -1; + + private final float mTouchSlop; + private final float mMinimumVelocity; + private final ScaleGestureDetector mScaleDetector; + private final OnScaleDragGestureListener mScaleDragGestureListener; + + private VelocityTracker mVelocityTracker; + private boolean mIsDragging; + float mLastTouchX; + float mLastTouchY; + private int mActivePointerId = INVALID_POINTER_ID; + private int mActivePointerIndex = 0; + + public ScaleDragDetector(Context context, OnScaleDragGestureListener scaleDragGestureListener) { + mScaleDetector = new ScaleGestureDetector(context, this); + mScaleDragGestureListener = scaleDragGestureListener; + + final ViewConfiguration configuration = ViewConfiguration.get(context); + mMinimumVelocity = configuration.getScaledMinimumFlingVelocity(); + mTouchSlop = configuration.getScaledTouchSlop(); + } + + @Override public boolean onScale(ScaleGestureDetector detector) { + float scaleFactor = detector.getScaleFactor(); + + if (Float.isNaN(scaleFactor) || Float.isInfinite(scaleFactor)) { + return false; + } + + mScaleDragGestureListener.onScale(scaleFactor, detector.getFocusX(), detector.getFocusY()); + return true; + } + + @Override public boolean onScaleBegin(ScaleGestureDetector detector) { + return true; + } + + @Override public void onScaleEnd(ScaleGestureDetector detector) { + mScaleDragGestureListener.onScaleEnd(); + } + + public boolean isScaling() { + return mScaleDetector.isInProgress(); + } + + public boolean isDragging() { + return mIsDragging; + } + + private float getActiveX(MotionEvent ev) { + try { + return MotionEventCompat.getX(ev, mActivePointerIndex); + } catch (Exception e) { + return ev.getX(); + } + } + + private float getActiveY(MotionEvent ev) { + try { + return MotionEventCompat.getY(ev, mActivePointerIndex); + } catch (Exception e) { + return ev.getY(); + } + } + + public boolean onTouchEvent(MotionEvent ev) { + mScaleDetector.onTouchEvent(ev); + final int action = MotionEventCompat.getActionMasked(ev); + onTouchActivePointer(action, ev); + onTouchDragEvent(action, ev); + return true; + } + + private void onTouchActivePointer(int action, MotionEvent ev) { + switch (action) { + case MotionEvent.ACTION_DOWN: + mActivePointerId = ev.getPointerId(0); + break; + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: + mActivePointerId = INVALID_POINTER_ID; + break; + case MotionEvent.ACTION_POINTER_UP: + final int pointerIndex = MotionEventCompat.getActionIndex(ev); + final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex); + if (pointerId == mActivePointerId) { + final int newPointerIndex = (pointerIndex == 0) ? 1 : 0; + mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex); + mLastTouchX = MotionEventCompat.getX(ev, newPointerIndex); + mLastTouchY = MotionEventCompat.getY(ev, newPointerIndex); + } + + break; + } + + mActivePointerIndex = MotionEventCompat.findPointerIndex(ev, + mActivePointerId != INVALID_POINTER_ID ? mActivePointerId : 0); + } + + private void onTouchDragEvent(int action, MotionEvent ev) { + switch (action) { + case MotionEvent.ACTION_DOWN: { + mVelocityTracker = VelocityTracker.obtain(); + if (null != mVelocityTracker) { + mVelocityTracker.addMovement(ev); + } + + mLastTouchX = getActiveX(ev); + mLastTouchY = getActiveY(ev); + mIsDragging = false; + break; + } + + case MotionEvent.ACTION_MOVE: { + final float x = getActiveX(ev); + final float y = getActiveY(ev); + final float dx = x - mLastTouchX, dy = y - mLastTouchY; + + if (!mIsDragging) { + mIsDragging = Math.sqrt((dx * dx) + (dy * dy)) >= mTouchSlop; + } + + if (mIsDragging) { + mScaleDragGestureListener.onDrag(dx, dy); + mLastTouchX = x; + mLastTouchY = y; + + if (null != mVelocityTracker) { + mVelocityTracker.addMovement(ev); + } + } + break; + } + + case MotionEvent.ACTION_CANCEL: { + if (null != mVelocityTracker) { + mVelocityTracker.recycle(); + mVelocityTracker = null; + } + break; + } + + case MotionEvent.ACTION_UP: { + if (mIsDragging) { + if (null != mVelocityTracker) { + mLastTouchX = getActiveX(ev); + mLastTouchY = getActiveY(ev); + + mVelocityTracker.addMovement(ev); + mVelocityTracker.computeCurrentVelocity(1000); + + final float vX = mVelocityTracker.getXVelocity(), vY = + mVelocityTracker.getYVelocity(); + + if (Math.max(Math.abs(vX), Math.abs(vY)) >= mMinimumVelocity) { + mScaleDragGestureListener.onFling(mLastTouchX, mLastTouchY, -vX, -vY); + } + } + } + if (null != mVelocityTracker) { + mVelocityTracker.recycle(); + mVelocityTracker = null; + } + break; + } + } + } +} diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/AbstractAnimatedZoomableController.java b/app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/AbstractAnimatedZoomableController.java deleted file mode 100644 index ff93b235..00000000 --- a/app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/AbstractAnimatedZoomableController.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * This file provided by Facebook is for non-commercial testing and evaluation - * purposes only. Facebook reserves all rights not expressly granted. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -package com.hiroshi.cimoc.ui.custom.zoomable; - -import android.graphics.Matrix; -import android.graphics.PointF; -import android.support.annotation.Nullable; - -import com.facebook.common.logging.FLog; - -/** - * Abstract class for ZoomableController that adds animation capabilities to - * DefaultZoomableController. - */ -public abstract class AbstractAnimatedZoomableController extends DefaultZoomableController { - - private boolean mIsAnimating; - private final float[] mStartValues = new float[9]; - private final float[] mStopValues = new float[9]; - private final float[] mCurrentValues = new float[9]; - private final Matrix mNewTransform = new Matrix(); - private final Matrix mWorkingTransform = new Matrix(); - - - public AbstractAnimatedZoomableController(TransformGestureDetector transformGestureDetector) { - super(transformGestureDetector); - } - - @Override - public void reset() { - FLog.v(getLogTag(), "reset"); - stopAnimation(); - mWorkingTransform.reset(); - mNewTransform.reset(); - super.reset(); - } - - /** - * Returns true if the zoomable transform is identity matrix, and the controller is idle. - */ - @Override - public boolean isIdentity() { - return !isAnimating() && super.isIdentity(); - } - - /** - * Zooms to the desired scale and positions the image so that the given image point corresponds - * to the given view point. - * - *

If this method is called while an animation or gesture is already in progress, - * the current animation or gesture will be stopped first. - * - * @param scale desired scale, will be limited to {min, max} scale factor - * @param imagePoint 2D point in image's relative coordinate system (i.e. 0 <= x, y <= 1) - * @param viewPoint 2D point in view's absolute coordinate system - */ - @Override - public void zoomToPoint( - float scale, - PointF imagePoint, - PointF viewPoint) { - zoomToPoint(scale, imagePoint, viewPoint, LIMIT_ALL, 0, null); - } - - /** - * Zooms to the desired scale and positions the image so that the given image point corresponds - * to the given view point. - * - *

If this method is called while an animation or gesture is already in progress, - * the current animation or gesture will be stopped first. - * - * @param scale desired scale, will be limited to {min, max} scale factor - * @param imagePoint 2D point in image's relative coordinate system (i.e. 0 <= x, y <= 1) - * @param viewPoint 2D point in view's absolute coordinate system - * @param limitFlags whether to limit translation and/or scale. - * @param durationMs length of animation of the zoom, or 0 if no animation desired - * @param onAnimationComplete code to run when the animation completes. Ignored if durationMs=0 - */ - public void zoomToPoint( - float scale, - PointF imagePoint, - PointF viewPoint, - @LimitFlag int limitFlags, - long durationMs, - @Nullable Runnable onAnimationComplete) { - FLog.v(getLogTag(), "zoomToPoint: duration %d ms", durationMs); - calculateZoomToPointTransform( - mNewTransform, - scale, - imagePoint, - viewPoint, - limitFlags); - setTransform(mNewTransform, durationMs, onAnimationComplete); - } - - /** - * Sets a new zoomable transformation and animates to it if desired. - * - *

If this method is called while an animation or gesture is already in progress, - * the current animation or gesture will be stopped first. - * - * @param newTransform new transform to make active - * @param durationMs duration of the animation, or 0 to not animate - * @param onAnimationComplete code to run when the animation completes. Ignored if durationMs=0 - */ - public void setTransform( - Matrix newTransform, - long durationMs, - @Nullable Runnable onAnimationComplete) { - FLog.v(getLogTag(), "setTransform: duration %d ms", durationMs); - if (durationMs <= 0) { - setTransformImmediate(newTransform); - } else { - setTransformAnimated(newTransform, durationMs, onAnimationComplete); - } - } - - private void setTransformImmediate(final Matrix newTransform) { - FLog.v(getLogTag(), "setTransformImmediate"); - stopAnimation(); - mWorkingTransform.set(newTransform); - super.setTransform(newTransform); - getDetector().restartGesture(); - } - - protected boolean isAnimating() { - return mIsAnimating; - } - - protected void setAnimating(boolean isAnimating) { - mIsAnimating = isAnimating; - } - - protected float[] getStartValues() { - return mStartValues; - } - - protected float[] getStopValues() { - return mStopValues; - } - - protected Matrix getWorkingTransform() { - return mWorkingTransform; - } - - @Override - public void onGestureBegin(TransformGestureDetector detector) { - FLog.v(getLogTag(), "onGestureBegin"); - stopAnimation(); - super.onGestureBegin(detector); - } - - @Override - public void onGestureUpdate(TransformGestureDetector detector) { - FLog.v(getLogTag(), "onGestureUpdate %s", isAnimating() ? "(ignored)" : ""); - if (isAnimating()) { - return; - } - super.onGestureUpdate(detector); - } - - protected void calculateInterpolation(Matrix outMatrix, float fraction) { - for (int i = 0; i < 9; i++) { - mCurrentValues[i] = (1 - fraction) * mStartValues[i] + fraction * mStopValues[i]; - } - outMatrix.setValues(mCurrentValues); - } - - public abstract void setTransformAnimated( - final Matrix newTransform, - long durationMs, - @Nullable final Runnable onAnimationComplete); - - protected abstract void stopAnimation(); - - protected abstract Class getLogTag(); -} \ No newline at end of file diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/AnimatedZoomableController.java b/app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/AnimatedZoomableController.java deleted file mode 100644 index ea20a57b..00000000 --- a/app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/AnimatedZoomableController.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * This file provided by Facebook is for non-commercial testing and evaluation - * purposes only. Facebook reserves all rights not expressly granted. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -package com.hiroshi.cimoc.ui.custom.zoomable; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ValueAnimator; -import android.annotation.SuppressLint; -import android.graphics.Matrix; -import android.support.annotation.Nullable; -import android.view.animation.DecelerateInterpolator; - -import com.facebook.common.internal.Preconditions; -import com.facebook.common.logging.FLog; - -/** - * ZoomableController that adds animation capabilities to DefaultZoomableController using standard - * Android animation classes - */ -public class AnimatedZoomableController extends AbstractAnimatedZoomableController { - - private static final Class TAG = AnimatedZoomableController.class; - - private final ValueAnimator mValueAnimator; - - public static AnimatedZoomableController newInstance() { - return new AnimatedZoomableController(TransformGestureDetector.newInstance()); - } - - @SuppressLint("NewApi") - public AnimatedZoomableController(TransformGestureDetector transformGestureDetector) { - super(transformGestureDetector); - mValueAnimator = ValueAnimator.ofFloat(0, 1); - mValueAnimator.setInterpolator(new DecelerateInterpolator()); - } - - @SuppressLint("NewApi") - @Override - public void setTransformAnimated( - final Matrix newTransform, - long durationMs, - @Nullable final Runnable onAnimationComplete) { - FLog.v(getLogTag(), "setTransformAnimated: duration %d ms", durationMs); - stopAnimation(); - Preconditions.checkArgument(durationMs > 0); - Preconditions.checkState(!isAnimating()); - setAnimating(true); - mValueAnimator.setDuration(durationMs); - getTransform().getValues(getStartValues()); - newTransform.getValues(getStopValues()); - mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator valueAnimator) { - calculateInterpolation(getWorkingTransform(), (float) valueAnimator.getAnimatedValue()); - AnimatedZoomableController.super.setTransform(getWorkingTransform()); - } - }); - mValueAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationCancel(Animator animation) { - FLog.v(getLogTag(), "setTransformAnimated: animation cancelled"); - onAnimationStopped(); - } - @Override - public void onAnimationEnd(Animator animation) { - FLog.v(getLogTag(), "setTransformAnimated: animation finished"); - onAnimationStopped(); - } - private void onAnimationStopped() { - if (onAnimationComplete != null) { - onAnimationComplete.run(); - } - setAnimating(false); - getDetector().restartGesture(); - } - }); - mValueAnimator.start(); - } - - @SuppressLint("NewApi") - @Override - public void stopAnimation() { - if (!isAnimating()) { - return; - } - FLog.v(getLogTag(), "stopAnimation"); - mValueAnimator.cancel(); - mValueAnimator.removeAllUpdateListeners(); - mValueAnimator.removeAllListeners(); - } - - @Override - protected Class getLogTag() { - return TAG; - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/AnimatedZoomableControllerSupport.java b/app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/AnimatedZoomableControllerSupport.java deleted file mode 100644 index ac1d57f0..00000000 --- a/app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/AnimatedZoomableControllerSupport.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * This file provided by Facebook is for non-commercial testing and evaluation - * purposes only. Facebook reserves all rights not expressly granted. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -package com.hiroshi.cimoc.ui.custom.zoomable; - -import android.graphics.Matrix; -import android.support.annotation.Nullable; -import android.view.animation.DecelerateInterpolator; - -import com.facebook.common.internal.Preconditions; -import com.facebook.common.logging.FLog; -import com.nineoldandroids.animation.Animator; -import com.nineoldandroids.animation.AnimatorListenerAdapter; -import com.nineoldandroids.animation.ValueAnimator; - -/** - * ZoomableController that adds animation capabilities to DefaultZoomableController using - * nineoldandroid library - */ -public class AnimatedZoomableControllerSupport extends AbstractAnimatedZoomableController { - - private static final Class TAG = AnimatedZoomableControllerSupport.class; - - private final ValueAnimator mValueAnimator; - - public static AnimatedZoomableControllerSupport newInstance() { - return new AnimatedZoomableControllerSupport(TransformGestureDetector.newInstance()); - } - - public AnimatedZoomableControllerSupport(TransformGestureDetector transformGestureDetector) { - super(transformGestureDetector); - mValueAnimator = ValueAnimator.ofFloat(0, 1); - mValueAnimator.setInterpolator(new DecelerateInterpolator()); - } - - public void setTransformAnimated( - final Matrix newTransform, - long durationMs, - @Nullable final Runnable onAnimationComplete) { - FLog.v(getLogTag(), "setTransformAnimated: duration %d ms", durationMs); - stopAnimation(); - Preconditions.checkArgument(durationMs > 0); - Preconditions.checkState(!isAnimating()); - setAnimating(true); - mValueAnimator.setDuration(durationMs); - getTransform().getValues(getStartValues()); - newTransform.getValues(getStopValues()); - mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator valueAnimator) { - calculateInterpolation(getWorkingTransform(), (float) valueAnimator.getAnimatedValue()); - AnimatedZoomableControllerSupport.super.setTransform(getWorkingTransform()); - } - }); - mValueAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationCancel(Animator animation) { - FLog.v(getLogTag(), "setTransformAnimated: animation cancelled"); - onAnimationStopped(); - } - @Override - public void onAnimationEnd(Animator animation) { - FLog.v(getLogTag(), "setTransformAnimated: animation finished"); - onAnimationStopped(); - } - private void onAnimationStopped() { - if (onAnimationComplete != null) { - onAnimationComplete.run(); - } - setAnimating(false); - getDetector().restartGesture(); - } - }); - mValueAnimator.start(); - } - - public void stopAnimation() { - if (!isAnimating()) { - return; - } - FLog.v(getLogTag(), "stopAnimation"); - mValueAnimator.cancel(); - mValueAnimator.removeAllUpdateListeners(); - mValueAnimator.removeAllListeners(); - } - - @Override - protected Class getLogTag() { - return TAG; - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/DefaultZoomableController.java b/app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/DefaultZoomableController.java deleted file mode 100644 index 24ca352c..00000000 --- a/app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/DefaultZoomableController.java +++ /dev/null @@ -1,579 +0,0 @@ -/* - * This file provided by Facebook is for non-commercial testing and evaluation - * purposes only. Facebook reserves all rights not expressly granted. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -package com.hiroshi.cimoc.ui.custom.zoomable; - -import android.graphics.Matrix; -import android.graphics.PointF; -import android.graphics.RectF; -import android.support.annotation.IntDef; -import android.view.MotionEvent; - -import com.facebook.common.logging.FLog; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Zoomable controller that calculates transformation based on touch events. - */ -public class DefaultZoomableController - implements ZoomableController, TransformGestureDetector.Listener { - - @IntDef(flag=true, value={ - LIMIT_NONE, - LIMIT_TRANSLATION_X, - LIMIT_TRANSLATION_Y, - LIMIT_SCALE, - LIMIT_ALL - }) - @Retention(RetentionPolicy.SOURCE) - public @interface LimitFlag {} - - public static final int LIMIT_NONE = 0; - public static final int LIMIT_TRANSLATION_X = 1; - public static final int LIMIT_TRANSLATION_Y = 2; - public static final int LIMIT_SCALE = 4; - public static final int LIMIT_ALL = LIMIT_TRANSLATION_X | LIMIT_TRANSLATION_Y | LIMIT_SCALE; - - private static final Class TAG = DefaultZoomableController.class; - - private static final RectF IDENTITY_RECT = new RectF(0, 0, 1, 1); - - private TransformGestureDetector mGestureDetector; - - private Listener mListener = null; - - private boolean mIsEnabled = false; - private boolean mIsRotationEnabled = false; - private boolean mIsScaleEnabled = true; - private boolean mIsTranslationEnabled = true; - - private float mMinScaleFactor = 1.0f; - private float mMaxScaleFactor = 2.0f; - - // View bounds, in view-absolute coordinates - private final RectF mViewBounds = new RectF(); - // Non-transformed image bounds, in view-absolute coordinates - private final RectF mImageBounds = new RectF(); - // Transformed image bounds, in view-absolute coordinates - private final RectF mTransformedImageBounds = new RectF(); - - private final Matrix mPreviousTransform = new Matrix(); - private final Matrix mActiveTransform = new Matrix(); - private final Matrix mActiveTransformInverse = new Matrix(); - private final float[] mTempValues = new float[9]; - private final RectF mTempRect = new RectF(); - private boolean mWasTransformedWithoutCorrection; - - public static DefaultZoomableController newInstance() { - return new DefaultZoomableController(TransformGestureDetector.newInstance()); - } - - public DefaultZoomableController(TransformGestureDetector gestureDetector) { - mGestureDetector = gestureDetector; - mGestureDetector.setListener(this); - } - - /** Rests the controller. */ - public void reset() { - FLog.v(TAG, "reset"); - mGestureDetector.reset(); - mPreviousTransform.reset(); - mActiveTransform.reset(); - onTransformChanged(); - } - - /** Sets the zoomable listener. */ - @Override - public void setListener(Listener listener) { - mListener = listener; - } - - /** Sets whether the controller is enabled or not. */ - @Override - public void setEnabled(boolean enabled) { - mIsEnabled = enabled; - if (!enabled) { - reset(); - } - } - - /** Gets whether the controller is enabled or not. */ - @Override - public boolean isEnabled() { - return mIsEnabled; - } - - /** Sets whether the rotation gesture is enabled or not. */ - public void setRotationEnabled(boolean enabled) { - mIsRotationEnabled = enabled; - } - - /** Gets whether the rotation gesture is enabled or not. */ - public boolean isRotationEnabled() { - return mIsRotationEnabled; - } - - /** Sets whether the scale gesture is enabled or not. */ - public void setScaleEnabled(boolean enabled) { - mIsScaleEnabled = enabled; - } - - /** Gets whether the scale gesture is enabled or not. */ - public boolean isScaleEnabled() { - return mIsScaleEnabled; - } - - /** Sets whether the translation gesture is enabled or not. */ - public void setTranslationEnabled(boolean enabled) { - mIsTranslationEnabled = enabled; - } - - /** Gets whether the translations gesture is enabled or not. */ - public boolean isTranslationEnabled() { - return mIsTranslationEnabled; - } - - /** - * Sets the minimum scale factor allowed. - *

Hierarchy's scaling (if any) is not taken into account. - */ - public void setMinScaleFactor(float minScaleFactor) { - mMinScaleFactor = minScaleFactor; - } - - /** Gets the minimum scale factor allowed. */ - public float getMinScaleFactor() { - return mMinScaleFactor; - } - - /** - * Sets the maximum scale factor allowed. - *

Hierarchy's scaling (if any) is not taken into account. - */ - public void setMaxScaleFactor(float maxScaleFactor) { - mMaxScaleFactor = maxScaleFactor; - } - - /** Gets the maximum scale factor allowed. */ - public float getMaxScaleFactor() { - return mMaxScaleFactor; - } - - /** Gets the current scale factor. */ - @Override - public float getScaleFactor() { - return getMatrixScaleFactor(mActiveTransform); - } - - /** Sets the image bounds, in view-absolute coordinates. */ - @Override - public void setImageBounds(RectF imageBounds) { - if (!imageBounds.equals(mImageBounds)) { - mImageBounds.set(imageBounds); - onTransformChanged(); - } - } - - /** Gets the non-transformed image bounds, in view-absolute coordinates. */ - public RectF getImageBounds() { - return mImageBounds; - } - - /** Gets the transformed image bounds, in view-absolute coordinates */ - private RectF getTransformedImageBounds() { - return mTransformedImageBounds; - } - - /** Sets the view bounds. */ - @Override - public void setViewBounds(RectF viewBounds) { - mViewBounds.set(viewBounds); - } - - /** Gets the view bounds. */ - public RectF getViewBounds() { - return mViewBounds; - } - - /** - * Returns true if the zoomable transform is identity matrix. - */ - @Override - public boolean isIdentity() { - return isMatrixIdentity(mActiveTransform, 1e-3f); - } - - /** - * Returns true if the transform was corrected during the last update. - * - * We should rename this method to `wasTransformedWithoutCorrection` and just return the - * internal flag directly. However, this requires interface change and negation of meaning. - */ - @Override - public boolean wasTransformCorrected() { - return !mWasTransformedWithoutCorrection; - } - - /** - * Gets the matrix that transforms image-absolute coordinates to view-absolute coordinates. - * The zoomable transformation is taken into account. - * - * Internal matrix is exposed for performance reasons and is not to be modified by the callers. - */ - @Override - public Matrix getTransform() { - return mActiveTransform; - } - - /** - * Gets the matrix that transforms image-relative coordinates to view-absolute coordinates. - * The zoomable transformation is taken into account. - */ - public void getImageRelativeToViewAbsoluteTransform(Matrix outMatrix) { - outMatrix.setRectToRect(IDENTITY_RECT, mTransformedImageBounds, Matrix.ScaleToFit.FILL); - } - - /** - * Maps point from view-absolute to image-relative coordinates. - * This takes into account the zoomable transformation. - */ - public PointF mapViewToImage(PointF viewPoint) { - float[] points = mTempValues; - points[0] = viewPoint.x; - points[1] = viewPoint.y; - mActiveTransform.invert(mActiveTransformInverse); - mActiveTransformInverse.mapPoints(points, 0, points, 0, 1); - mapAbsoluteToRelative(points, points, 1); - return new PointF(points[0], points[1]); - } - - /** - * Maps point from image-relative to view-absolute coordinates. - * This takes into account the zoomable transformation. - */ - public PointF mapImageToView(PointF imagePoint) { - float[] points = mTempValues; - points[0] = imagePoint.x; - points[1] = imagePoint.y; - mapRelativeToAbsolute(points, points, 1); - mActiveTransform.mapPoints(points, 0, points, 0, 1); - return new PointF(points[0], points[1]); - } - - /** - * Maps array of 2D points from view-absolute to image-relative coordinates. - * This does NOT take into account the zoomable transformation. - * Points are represented by a float array of [x0, y0, x1, y1, ...]. - * - * @param destPoints destination array (may be the same as source array) - * @param srcPoints source array - * @param numPoints number of points to map - */ - private void mapAbsoluteToRelative(float[] destPoints, float[] srcPoints, int numPoints) { - for (int i = 0; i < numPoints; i++) { - destPoints[i * 2 + 0] = (srcPoints[i * 2 + 0] - mImageBounds.left) / mImageBounds.width(); - destPoints[i * 2 + 1] = (srcPoints[i * 2 + 1] - mImageBounds.top) / mImageBounds.height(); - } - } - - /** - * Maps array of 2D points from image-relative to view-absolute coordinates. - * This does NOT take into account the zoomable transformation. - * Points are represented by float array of [x0, y0, x1, y1, ...]. - * - * @param destPoints destination array (may be the same as source array) - * @param srcPoints source array - * @param numPoints number of points to map - */ - private void mapRelativeToAbsolute(float[] destPoints, float[] srcPoints, int numPoints) { - for (int i = 0; i < numPoints; i++) { - destPoints[i * 2 + 0] = srcPoints[i * 2 + 0] * mImageBounds.width() + mImageBounds.left; - destPoints[i * 2 + 1] = srcPoints[i * 2 + 1] * mImageBounds.height() + mImageBounds.top; - } - } - - /** - * Zooms to the desired scale and positions the image so that the given image point corresponds - * to the given view point. - * - * @param scale desired scale, will be limited to {min, max} scale factor - * @param imagePoint 2D point in image's relative coordinate system (i.e. 0 <= x, y <= 1) - * @param viewPoint 2D point in view's absolute coordinate system - */ - public void zoomToPoint(float scale, PointF imagePoint, PointF viewPoint) { - FLog.v(TAG, "zoomToPoint"); - calculateZoomToPointTransform(mActiveTransform, scale, imagePoint, viewPoint, LIMIT_ALL); - onTransformChanged(); - } - - /** - * Calculates the zoom transformation that would zoom to the desired scale and position the image - * so that the given image point corresponds to the given view point. - * - * @param outTransform the matrix to store the result to - * @param scale desired scale, will be limited to {min, max} scale factor - * @param imagePoint 2D point in image's relative coordinate system (i.e. 0 <= x, y <= 1) - * @param viewPoint 2D point in view's absolute coordinate system - * @param limitFlags whether to limit translation and/or scale. - * @return whether or not the transform has been corrected due to limitation - */ - protected boolean calculateZoomToPointTransform( - Matrix outTransform, - float scale, - PointF imagePoint, - PointF viewPoint, - @LimitFlag int limitFlags) { - float[] viewAbsolute = mTempValues; - viewAbsolute[0] = imagePoint.x; - viewAbsolute[1] = imagePoint.y; - mapRelativeToAbsolute(viewAbsolute, viewAbsolute, 1); - float distanceX = viewPoint.x - viewAbsolute[0]; - float distanceY = viewPoint.y - viewAbsolute[1]; - boolean transformCorrected = false; - outTransform.setScale(scale, scale, viewAbsolute[0], viewAbsolute[1]); - transformCorrected |= limitScale(outTransform, viewAbsolute[0], viewAbsolute[1], limitFlags); - outTransform.postTranslate(distanceX, distanceY); - transformCorrected |= limitTranslation(outTransform, limitFlags); - return transformCorrected; - } - - /** Sets a new zoom transformation. */ - public void setTransform(Matrix newTransform) { - FLog.v(TAG, "setTransform"); - mActiveTransform.set(newTransform); - onTransformChanged(); - } - - /** Gets the gesture detector. */ - protected TransformGestureDetector getDetector() { - return mGestureDetector; - } - - /** Notifies controller of the received touch event. */ - @Override - public boolean onTouchEvent(MotionEvent event) { - FLog.v(TAG, "onTouchEvent: action: ", event.getAction()); - if (mIsEnabled) { - return mGestureDetector.onTouchEvent(event); - } - return false; - } - - /* TransformGestureDetector.Listener methods */ - - @Override - public void onGestureBegin(TransformGestureDetector detector) { - FLog.v(TAG, "onGestureBegin"); - mPreviousTransform.set(mActiveTransform); - // We started the gesture, but no transformation occurred just yet. - mWasTransformedWithoutCorrection = false; - } - - @Override - public void onGestureUpdate(TransformGestureDetector detector) { - FLog.v(TAG, "onGestureUpdate"); - boolean transformCorrected = calculateGestureTransform(mActiveTransform, LIMIT_ALL); - onTransformChanged(); - if (transformCorrected) { - mGestureDetector.restartGesture(); - } - // A transformation happened, but was it without correction? - mWasTransformedWithoutCorrection = !transformCorrected; - } - - @Override - public void onGestureEnd(TransformGestureDetector detector) { - FLog.v(TAG, "onGestureEnd"); - } - - /** - * Calculates the zoom transformation based on the current gesture. - * - * @param outTransform the matrix to store the result to - * @param limitTypes whether to limit translation and/or scale. - * @return whether or not the transform has been corrected due to limitation - */ - protected boolean calculateGestureTransform( - Matrix outTransform, - @LimitFlag int limitTypes) { - TransformGestureDetector detector = mGestureDetector; - boolean transformCorrected = false; - outTransform.set(mPreviousTransform); - if (mIsRotationEnabled) { - float angle = detector.getRotation() * (float) (180 / Math.PI); - outTransform.postRotate(angle, detector.getPivotX(), detector.getPivotY()); - } - if (mIsScaleEnabled) { - float scale = detector.getScale(); - outTransform.postScale(scale, scale, detector.getPivotX(), detector.getPivotY()); - } - transformCorrected |= - limitScale(outTransform, detector.getPivotX(), detector.getPivotY(), limitTypes); - if (mIsTranslationEnabled) { - outTransform.postTranslate(detector.getTranslationX(), detector.getTranslationY()); - } - transformCorrected |= limitTranslation(outTransform, limitTypes); - return transformCorrected; - } - - private void onTransformChanged() { - mActiveTransform.mapRect(mTransformedImageBounds, mImageBounds); - if (mListener != null && isEnabled()) { - mListener.onTransformChanged(mActiveTransform); - } - } - - /** - * Keeps the scaling factor within the specified limits. - * - * @param pivotX x coordinate of the pivot point - * @param pivotY y coordinate of the pivot point - * @param limitTypes whether to limit scale. - * @return whether limiting has been applied or not - */ - private boolean limitScale( - Matrix transform, - float pivotX, - float pivotY, - @LimitFlag int limitTypes) { - if (!shouldLimit(limitTypes, LIMIT_SCALE)) { - return false; - } - float currentScale = getMatrixScaleFactor(transform); - float targetScale = limit(currentScale, mMinScaleFactor, mMaxScaleFactor); - if (targetScale != currentScale) { - float scale = targetScale / currentScale; - transform.postScale(scale, scale, pivotX, pivotY); - return true; - } - return false; - } - - /** - * Limits the translation so that there are no empty spaces on the sides if possible. - * - *

The image is attempted to be centered within the view bounds if the transformed image is - * smaller. There will be no empty spaces within the view bounds if the transformed image is - * bigger. This applies to each dimension (horizontal and vertical) independently. - * - * @param limitTypes whether to limit translation along the specific axis. - * @return whether limiting has been applied or not - */ - private boolean limitTranslation(Matrix transform, @LimitFlag int limitTypes) { - if (!shouldLimit(limitTypes, LIMIT_TRANSLATION_X | LIMIT_TRANSLATION_Y)) { - return false; - } - RectF b = mTempRect; - b.set(mImageBounds); - transform.mapRect(b); - float offsetLeft = shouldLimit(limitTypes, LIMIT_TRANSLATION_X) ? - getOffset(b.left, b.right, mViewBounds.left, mViewBounds.right, mImageBounds.centerX()) : 0; - float offsetTop = shouldLimit(limitTypes, LIMIT_TRANSLATION_Y) ? - getOffset(b.top, b.bottom, mViewBounds.top, mViewBounds.bottom, mImageBounds.centerY()) : 0; - if (offsetLeft != 0 || offsetTop != 0) { - transform.postTranslate(offsetLeft, offsetTop); - return true; - } - return false; - } - - /** - * Checks whether the specified limit flag is present in the limits provided. - * - *

If the flag contains multiple flags together using a bitwise OR, this only checks that at - * least one of the flags is included. - * - * @param limits the limits to apply - * @param flag the limit flag(s) to check for - * @return true if the flag (or one of the flags) is included in the limits - */ - private static boolean shouldLimit(@LimitFlag int limits, @LimitFlag int flag) { - return (limits & flag) != LIMIT_NONE; - } - - /** - * Returns the offset necessary to make sure that: - * - the image is centered within the limit if the image is smaller than the limit - * - there is no empty space on left/right if the image is bigger than the limit - */ - private float getOffset( - float imageStart, - float imageEnd, - float limitStart, - float limitEnd, - float limitCenter) { - float imageWidth = imageEnd - imageStart, limitWidth = limitEnd - limitStart; - float limitInnerWidth = Math.min(limitCenter - limitStart, limitEnd - limitCenter) * 2; - // center if smaller than limitInnerWidth - if (imageWidth < limitInnerWidth) { - return limitCenter - (imageEnd + imageStart) / 2; - } - // to the edge if in between and limitCenter is not (limitLeft + limitRight) / 2 - if (imageWidth < limitWidth) { - if (limitCenter < (limitStart + limitEnd) / 2) { - return limitStart - imageStart; - } else { - return limitEnd - imageEnd; - } - } - // to the edge if larger than limitWidth and empty space visible - if (imageStart > limitStart) { - return limitStart - imageStart; - } - if (imageEnd < limitEnd) { - return limitEnd - imageEnd; - } - return 0; - } - - /** - * Limits the value to the given min and max range. - */ - private float limit(float value, float min, float max) { - return Math.min(Math.max(min, value), max); - } - - /** - * Gets the scale factor for the given matrix. - * This method assumes the equal scaling factor for X and Y axis. - */ - private float getMatrixScaleFactor(Matrix transform) { - transform.getValues(mTempValues); - return mTempValues[Matrix.MSCALE_X]; - } - - /** - * Same as {@code Matrix.isIdentity()}, but with tolerance {@code eps}. - */ - private boolean isMatrixIdentity(Matrix transform, float eps) { - // Checks whether the given matrix is close enough to the identity matrix: - // 1 0 0 - // 0 1 0 - // 0 0 1 - // Or equivalently to the zero matrix, after subtracting 1.0f from the diagonal elements: - // 0 0 0 - // 0 0 0 - // 0 0 0 - transform.getValues(mTempValues); - mTempValues[0] -= 1.0f; // m00 - mTempValues[4] -= 1.0f; // m11 - mTempValues[8] -= 1.0f; // m22 - for (int i = 0; i < 9; i++) { - if (Math.abs(mTempValues[i]) > eps) { - return false; - } - } - return true; - } -} \ No newline at end of file diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/GestureListenerWrapper.java b/app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/GestureListenerWrapper.java deleted file mode 100644 index 03b71512..00000000 --- a/app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/GestureListenerWrapper.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * This file provided by Facebook is for non-commercial testing and evaluation - * purposes only. Facebook reserves all rights not expressly granted. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -package com.hiroshi.cimoc.ui.custom.zoomable; - -import android.view.GestureDetector; -import android.view.MotionEvent; - -/** - * Wrapper for SimpleOnGestureListener as GestureDetector does not allow changing its listener. - */ -public class GestureListenerWrapper extends GestureDetector.SimpleOnGestureListener { - - private GestureDetector.SimpleOnGestureListener mDelegate; - - public GestureListenerWrapper() { - mDelegate = new GestureDetector.SimpleOnGestureListener(); - } - - public void setListener(GestureDetector.SimpleOnGestureListener listener) { - mDelegate = listener; - } - - @Override - public void onLongPress(MotionEvent e) { - mDelegate.onLongPress(e); - } - - @Override - public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { - return mDelegate.onScroll(e1, e2, distanceX, distanceY); - } - - @Override - public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { - return mDelegate.onFling(e1, e2, velocityX, velocityY); - } - - @Override - public void onShowPress(MotionEvent e) { - mDelegate.onShowPress(e); - } - - @Override - public boolean onDown(MotionEvent e) { - return mDelegate.onDown(e); - } - - @Override - public boolean onDoubleTap(MotionEvent e) { - return mDelegate.onDoubleTap(e); - } - - @Override - public boolean onDoubleTapEvent(MotionEvent e) { - return mDelegate.onDoubleTapEvent(e); - } - - @Override - public boolean onSingleTapConfirmed(MotionEvent e) { - return mDelegate.onSingleTapConfirmed(e); - } - - @Override - public boolean onSingleTapUp(MotionEvent e) { - return mDelegate.onSingleTapUp(e); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/MultiPointerGestureDetector.java b/app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/MultiPointerGestureDetector.java deleted file mode 100644 index 2b75663f..00000000 --- a/app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/MultiPointerGestureDetector.java +++ /dev/null @@ -1,271 +0,0 @@ -/* - * This file provided by Facebook is for non-commercial testing and evaluation - * purposes only. Facebook reserves all rights not expressly granted. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -package com.hiroshi.cimoc.ui.custom.zoomable; - -import android.view.MotionEvent; - -/** - * Component that detects and tracks multiple pointers based on touch events. - *

- * Each time a pointer gets pressed or released, the current gesture (if any) will end, and a new - * one will be started (if there are still pressed pointers left). It is guaranteed that the number - * of pointers within the single gesture will remain the same during the whole gesture. - */ -public class MultiPointerGestureDetector { - - /** The listener for receiving notifications when gestures occur. */ - public interface Listener { - /** A callback called right before the gesture is about to start. */ - public void onGestureBegin(MultiPointerGestureDetector detector); - - /** A callback called each time the gesture gets updated. */ - public void onGestureUpdate(MultiPointerGestureDetector detector); - - /** A callback called right after the gesture has finished. */ - public void onGestureEnd(MultiPointerGestureDetector detector); - } - - private static final int MAX_POINTERS = 2; - - private boolean mGestureInProgress; - private int mPointerCount; - private int mNewPointerCount; - private final int mId[] = new int[MAX_POINTERS]; - private final float mStartX[] = new float[MAX_POINTERS]; - private final float mStartY[] = new float[MAX_POINTERS]; - private final float mCurrentX[] = new float[MAX_POINTERS]; - private final float mCurrentY[] = new float[MAX_POINTERS]; - - private Listener mListener = null; - - public MultiPointerGestureDetector() { - reset(); - } - - /** Factory method that creates a new instance of MultiPointerGestureDetector */ - public static MultiPointerGestureDetector newInstance() { - return new MultiPointerGestureDetector(); - } - - /** - * Sets the listener. - * @param listener listener to set - */ - public void setListener(Listener listener) { - mListener = listener; - } - - /** - * Resets the component to the initial state. - */ - public void reset() { - mGestureInProgress = false; - mPointerCount = 0; - for (int i = 0; i < MAX_POINTERS; i++) { - mId[i] = MotionEvent.INVALID_POINTER_ID; - } - } - - /** - * This method can be overridden in order to perform threshold check or something similar. - * @return whether or not to start a new gesture - */ - protected boolean shouldStartGesture() { - return true; - } - - /** - * Starts a new gesture and calls the listener just before starting it. - */ - private void startGesture() { - if (!mGestureInProgress) { - if (mListener != null) { - mListener.onGestureBegin(this); - } - mGestureInProgress = true; - } - } - - /** - * Stops the current gesture and calls the listener right after stopping it. - */ - private void stopGesture() { - if (mGestureInProgress) { - mGestureInProgress = false; - if (mListener != null) { - mListener.onGestureEnd(this); - } - } - } - - /** - * Gets the index of the i-th pressed pointer. - * Normally, the index will be equal to i, except in the case when the pointer is released. - * @return index of the specified pointer or -1 if not found (i.e. not enough pointers are down) - */ - private int getPressedPointerIndex(MotionEvent event, int i) { - final int count = event.getPointerCount(); - final int action = event.getActionMasked(); - final int index = event.getActionIndex(); - if (action == MotionEvent.ACTION_UP || - action == MotionEvent.ACTION_POINTER_UP) { - if (i >= index) { - i++; - } - } - return (i < count) ? i : -1; - } - - /** - * Gets the number of pressed pointers (fingers down). - */ - private static int getPressedPointerCount(MotionEvent event) { - int count = event.getPointerCount(); - int action = event.getActionMasked(); - if (action == MotionEvent.ACTION_UP || - action == MotionEvent.ACTION_POINTER_UP) { - count--; - } - return count; - } - - private void updatePointersOnTap(MotionEvent event) { - mPointerCount = 0; - for (int i = 0; i < MAX_POINTERS; i++) { - int index = getPressedPointerIndex(event, i); - if (index == -1) { - mId[i] = MotionEvent.INVALID_POINTER_ID; - } else { - mId[i] = event.getPointerId(index); - mCurrentX[i] = mStartX[i] = event.getX(index); - mCurrentY[i] = mStartY[i] = event.getY(index); - mPointerCount++; - } - } - } - - private void updatePointersOnMove(MotionEvent event) { - for (int i = 0; i < MAX_POINTERS; i++) { - int index = event.findPointerIndex(mId[i]); - if (index != -1) { - mCurrentX[i] = event.getX(index); - mCurrentY[i] = event.getY(index); - } - } - } - - /** - * Handles the given motion event. - * @param event event to handle - * @return whether or not the event was handled - */ - public boolean onTouchEvent(final MotionEvent event) { - switch (event.getActionMasked()) { - case MotionEvent.ACTION_MOVE: { - // update pointers - updatePointersOnMove(event); - // start a new gesture if not already started - if (!mGestureInProgress && mPointerCount > 0 && shouldStartGesture()) { - startGesture(); - } - // notify listener - if (mGestureInProgress && mListener != null) { - mListener.onGestureUpdate(this); - } - break; - } - - case MotionEvent.ACTION_DOWN: - case MotionEvent.ACTION_POINTER_DOWN: - case MotionEvent.ACTION_POINTER_UP: - case MotionEvent.ACTION_UP: { - // restart gesture whenever the number of pointers changes - mNewPointerCount = getPressedPointerCount(event); - stopGesture(); - updatePointersOnTap(event); - if (mPointerCount > 0 && shouldStartGesture()) { - startGesture(); - } - break; - } - - case MotionEvent.ACTION_CANCEL: { - mNewPointerCount = 0; - stopGesture(); - reset(); - break; - } - } - return true; - } - - /** Restarts the current gesture (if any). */ - public void restartGesture() { - if (!mGestureInProgress) { - return; - } - stopGesture(); - for (int i = 0; i < MAX_POINTERS; i++) { - mStartX[i] = mCurrentX[i]; - mStartY[i] = mCurrentY[i]; - } - startGesture(); - } - - /** Gets whether there is a gesture in progress */ - public boolean isGestureInProgress() { - return mGestureInProgress; - } - - /** Gets the number of pointers after the current gesture */ - public int getNewPointerCount() { - return mNewPointerCount; - } - - /** Gets the number of pointers in the current gesture */ - public int getPointerCount() { - return mPointerCount; - } - - /** - * Gets the start X coordinates for the all pointers - * Mutable array is exposed for performance reasons and is not to be modified by the callers. - */ - public float[] getStartX() { - return mStartX; - } - - /** - * Gets the start Y coordinates for the all pointers - * Mutable array is exposed for performance reasons and is not to be modified by the callers. - */ - public float[] getStartY() { - return mStartY; - } - - /** - * Gets the current X coordinates for the all pointers - * Mutable array is exposed for performance reasons and is not to be modified by the callers. - */ - public float[] getCurrentX() { - return mCurrentX; - } - - /** - * Gets the current Y coordinates for the all pointers - * Mutable array is exposed for performance reasons and is not to be modified by the callers. - */ - public float[] getCurrentY() { - return mCurrentY; - } -} \ No newline at end of file diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/TransformGestureDetector.java b/app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/TransformGestureDetector.java deleted file mode 100644 index 80645edd..00000000 --- a/app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/TransformGestureDetector.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * This file provided by Facebook is for non-commercial testing and evaluation - * purposes only. Facebook reserves all rights not expressly granted. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -package com.hiroshi.cimoc.ui.custom.zoomable; - -import android.view.MotionEvent; - -/** - * Component that detects translation, scale and rotation based on touch events. - *

- * This class notifies its listeners whenever a gesture begins, updates or ends. - * The instance of this detector is passed to the listeners, so it can be queried - * for pivot, translation, scale or rotation. - */ -public class TransformGestureDetector implements MultiPointerGestureDetector.Listener { - - /** The listener for receiving notifications when gestures occur. */ - public interface Listener { - /** A callback called right before the gesture is about to start. */ - public void onGestureBegin(TransformGestureDetector detector); - - /** A callback called each time the gesture gets updated. */ - public void onGestureUpdate(TransformGestureDetector detector); - - /** A callback called right after the gesture has finished. */ - public void onGestureEnd(TransformGestureDetector detector); - } - - private final MultiPointerGestureDetector mDetector; - - private Listener mListener = null; - - public TransformGestureDetector(MultiPointerGestureDetector multiPointerGestureDetector) { - mDetector = multiPointerGestureDetector; - mDetector.setListener(this); - } - - /** Factory method that creates a new instance of TransformGestureDetector */ - public static TransformGestureDetector newInstance() { - return new TransformGestureDetector(MultiPointerGestureDetector.newInstance()); - } - - /** - * Sets the listener. - * @param listener listener to set - */ - public void setListener(Listener listener) { - mListener = listener; - } - - /** - * Resets the component to the initial state. - */ - public void reset() { - mDetector.reset(); - } - - /** - * Handles the given motion event. - * @param event event to handle - * @return whether or not the event was handled - */ - public boolean onTouchEvent(final MotionEvent event) { - return mDetector.onTouchEvent(event); - } - - @Override - public void onGestureBegin(MultiPointerGestureDetector detector) { - if (mListener != null) { - mListener.onGestureBegin(this); - } - } - - @Override - public void onGestureUpdate(MultiPointerGestureDetector detector) { - if (mListener != null) { - mListener.onGestureUpdate(this); - } - } - - @Override - public void onGestureEnd(MultiPointerGestureDetector detector) { - if (mListener != null) { - mListener.onGestureEnd(this); - } - } - - private float calcAverage(float[] arr, int len) { - float sum = 0; - for (int i = 0; i < len; i++) { - sum += arr[i]; - } - return (len > 0) ? sum / len : 0; - } - - /** Restarts the current gesture (if any). */ - public void restartGesture() { - mDetector.restartGesture(); - } - - /** Gets whether there is a gesture in progress */ - public boolean isGestureInProgress() { - return mDetector.isGestureInProgress(); - } - - /** Gets the number of pointers after the current gesture */ - public int getNewPointerCount() { - return mDetector.getNewPointerCount(); - } - - /** Gets the number of pointers in the current gesture */ - public int getPointerCount() { - return mDetector.getPointerCount(); - } - - /** Gets the X coordinate of the pivot point */ - public float getPivotX() { - return calcAverage(mDetector.getStartX(), mDetector.getPointerCount()); - } - - /** Gets the Y coordinate of the pivot point */ - public float getPivotY() { - return calcAverage(mDetector.getStartY(), mDetector.getPointerCount()); - } - - /** Gets the X component of the translation */ - public float getTranslationX() { - return calcAverage(mDetector.getCurrentX(), mDetector.getPointerCount()) - - calcAverage(mDetector.getStartX(), mDetector.getPointerCount()); - } - - /** Gets the Y component of the translation */ - public float getTranslationY() { - return calcAverage(mDetector.getCurrentY(), mDetector.getPointerCount()) - - calcAverage(mDetector.getStartY(), mDetector.getPointerCount()); - } - - /** Gets the scale */ - public float getScale() { - if (mDetector.getPointerCount() < 2) { - return 1; - } else { - float startDeltaX = mDetector.getStartX()[1] - mDetector.getStartX()[0]; - float startDeltaY = mDetector.getStartY()[1] - mDetector.getStartY()[0]; - float currentDeltaX = mDetector.getCurrentX()[1] - mDetector.getCurrentX()[0]; - float currentDeltaY = mDetector.getCurrentY()[1] - mDetector.getCurrentY()[0]; - float startDist = (float) Math.hypot(startDeltaX, startDeltaY); - float currentDist = (float) Math.hypot(currentDeltaX, currentDeltaY); - return currentDist / startDist; - } - } - - /** Gets the rotation in radians */ - public float getRotation() { - if (mDetector.getPointerCount() < 2) { - return 0; - } else { - float startDeltaX = mDetector.getStartX()[1] - mDetector.getStartX()[0]; - float startDeltaY = mDetector.getStartY()[1] - mDetector.getStartY()[0]; - float currentDeltaX = mDetector.getCurrentX()[1] - mDetector.getCurrentX()[0]; - float currentDeltaY = mDetector.getCurrentY()[1] - mDetector.getCurrentY()[0]; - float startAngle = (float) Math.atan2(startDeltaY, startDeltaX); - float currentAngle = (float) Math.atan2(currentDeltaY, currentDeltaX); - return currentAngle - startAngle; - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/ZoomableController.java b/app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/ZoomableController.java deleted file mode 100644 index b0c2a8fc..00000000 --- a/app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/ZoomableController.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * This file provided by Facebook is for non-commercial testing and evaluation - * purposes only. Facebook reserves all rights not expressly granted. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -package com.hiroshi.cimoc.ui.custom.zoomable; - -import android.graphics.Matrix; -import android.graphics.RectF; -import android.view.MotionEvent; - -/** - * Interface for implementing a controller that works with {@link ZoomableDraweeView} - * to control the zoom. - */ -public interface ZoomableController { - - /** - * Listener interface. - */ - interface Listener { - - /** - * Notifies the view that the transform changed. - * - * @param transform the new matrix - */ - void onTransformChanged(Matrix transform); - } - - /** - * Enables the controller. The controller is enabled when the image has been loaded. - * - * @param enabled whether to enable the controller - */ - void setEnabled(boolean enabled); - - /** - * Gets whether the controller is enabled. This should return the last value passed to - * {@link #setEnabled}. - * - * @return whether the controller is enabled. - */ - boolean isEnabled(); - - /** - * Sets the listener for the controller to call back when the matrix changes. - * - * @param listener the listener - */ - void setListener(Listener listener); - - /** - * Gets the current scale factor. A convenience method for calculating the scale from the - * transform. - * - * @return the current scale factor - */ - float getScaleFactor(); - - /** - * Returns true if the zoomable transform is identity matrix, and the controller is idle. - */ - boolean isIdentity(); - - /** - * Returns true if the transform was corrected during the last update. - * - * This mainly happens when a gesture would cause the image to get out of limits and the - * transform gets corrected in order to prevent that. - */ - boolean wasTransformCorrected(); - - /** - * Gets the current transform. - * - * @return the transform - */ - Matrix getTransform(); - - /** - * Sets the bounds of the image post transform prior to application of the zoomable - * transformation. - * - * @param imageBounds the bounds of the image - */ - void setImageBounds(RectF imageBounds); - - /** - * Sets the bounds of the view. - * - * @param viewBounds the bounds of the view - */ - void setViewBounds(RectF viewBounds); - - /** - * Allows the controller to handle a touch event. - * - * @param event the touch event - * @return whether the controller handled the event - */ - boolean onTouchEvent(MotionEvent event); -} \ No newline at end of file diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/ZoomableDraweeView.java b/app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/ZoomableDraweeView.java deleted file mode 100644 index 53c06495..00000000 --- a/app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/ZoomableDraweeView.java +++ /dev/null @@ -1,335 +0,0 @@ -/* - * This file provided by Facebook is for non-commercial testing and evaluation - * purposes only. Facebook reserves all rights not expressly granted. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -package com.hiroshi.cimoc.ui.custom.zoomable; - -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Canvas; -import android.graphics.Matrix; -import android.graphics.RectF; -import android.graphics.drawable.Animatable; -import android.support.annotation.Nullable; -import android.util.AttributeSet; -import android.view.GestureDetector; -import android.view.MotionEvent; - -import com.facebook.common.internal.Preconditions; -import com.facebook.common.logging.FLog; -import com.facebook.drawee.controller.AbstractDraweeController; -import com.facebook.drawee.controller.BaseControllerListener; -import com.facebook.drawee.controller.ControllerListener; -import com.facebook.drawee.drawable.ScalingUtils; -import com.facebook.drawee.generic.GenericDraweeHierarchy; -import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder; -import com.facebook.drawee.generic.GenericDraweeHierarchyInflater; -import com.facebook.drawee.interfaces.DraweeController; -import com.facebook.drawee.view.DraweeView; - -/** - * DraweeView that has zoomable capabilities. - *

- * Once the image loads, pinch-to-zoom and translation gestures are enabled. - */ -public class ZoomableDraweeView extends DraweeView { - - private static final Class TAG = ZoomableDraweeView.class; - - private static final float HUGE_IMAGE_SCALE_FACTOR_THRESHOLD = 1.1f; - - private final RectF mImageBounds = new RectF(); - private final RectF mViewBounds = new RectF(); - - private DraweeController mHugeImageController; - private ZoomableController mZoomableController; - private GestureDetector mTapGestureDetector; - - private final ControllerListener mControllerListener = new BaseControllerListener() { - @Override - public void onFinalImageSet( - String id, - @Nullable Object imageInfo, - @Nullable Animatable animatable) { - ZoomableDraweeView.this.onFinalImageSet(); - } - - @Override - public void onRelease(String id) { - ZoomableDraweeView.this.onRelease(); - } - }; - - private final ZoomableController.Listener mZoomableListener = new ZoomableController.Listener() { - @Override - public void onTransformChanged(Matrix transform) { - ZoomableDraweeView.this.onTransformChanged(transform); - } - }; - - private final GestureListenerWrapper mTapListenerWrapper = new GestureListenerWrapper(); - - public ZoomableDraweeView(Context context, GenericDraweeHierarchy hierarchy) { - super(context); - setHierarchy(hierarchy); - init(); - } - - public ZoomableDraweeView(Context context) { - super(context); - inflateHierarchy(context, null); - init(); - } - - public ZoomableDraweeView(Context context, AttributeSet attrs) { - super(context, attrs); - inflateHierarchy(context, attrs); - init(); - } - - public ZoomableDraweeView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - inflateHierarchy(context, attrs); - init(); - } - - protected void inflateHierarchy(Context context, @Nullable AttributeSet attrs) { - Resources resources = context.getResources(); - GenericDraweeHierarchyBuilder builder = new GenericDraweeHierarchyBuilder(resources) - .setActualImageScaleType(ScalingUtils.ScaleType.FIT_CENTER); - GenericDraweeHierarchyInflater.updateBuilder(builder, context, attrs); - setAspectRatio(builder.getDesiredAspectRatio()); - setHierarchy(builder.build()); - } - - private void init() { - mZoomableController = createZoomableController(); - mZoomableController.setListener(mZoomableListener); - mTapGestureDetector = new GestureDetector(getContext(), mTapListenerWrapper); - } - - /** - * Gets the original image bounds, in view-absolute coordinates. - * - *

The original image bounds are those reported by the hierarchy. The hierarchy itself may - * apply scaling on its own (e.g. due to scale type) so the reported bounds are not necessarily - * the same as the actual bitmap dimensions. In other words, the original image bounds correspond - * to the image bounds within this view when no zoomable transformation is applied, but including - * the potential scaling of the hierarchy. - * Having the actual bitmap dimensions abstracted away from this view greatly simplifies - * implementation because the actual bitmap may change (e.g. when a high-res image arrives and - * replaces the previously set low-res image). With proper hierarchy scaling (e.g. FIT_CENTER), - * this underlying change will not affect this view nor the zoomable transformation in any way. - */ - protected void getImageBounds(RectF outBounds) { - getHierarchy().getActualImageBounds(outBounds); - } - - /** - * Gets the bounds used to limit the translation, in view-absolute coordinates. - * - *

These bounds are passed to the zoomable controller in order to limit the translation. The - * image is attempted to be centered within the limit bounds if the transformed image is smaller. - * There will be no empty spaces within the limit bounds if the transformed image is bigger. - * This applies to each dimension (horizontal and vertical) independently. - *

Unless overridden by a subclass, these bounds are same as the view bounds. - */ - protected void getLimitBounds(RectF outBounds) { - outBounds.set(0, 0, getWidth(), getHeight()); - } - - /** - * Sets a custom zoomable controller, instead of using the default one. - */ - public void setZoomableController(ZoomableController zoomableController) { - Preconditions.checkNotNull(zoomableController); - mZoomableController.setListener(null); - mZoomableController = zoomableController; - mZoomableController.setListener(mZoomableListener); - } - - /** - * Gets the zoomable controller. - * - *

Zoomable controller can be used to zoom to point, or to map point from view to image - * coordinates for instance. - */ - public ZoomableController getZoomableController() { - return mZoomableController; - } - - /** - * Sets the tap listener. - */ - public void setTapListener(GestureDetector.SimpleOnGestureListener tapListener) { - mTapListenerWrapper.setListener(tapListener); - } - - /** - * Sets whether long-press tap detection is enabled. - * Unfortunately, long-press conflicts with onDoubleTapEvent. - */ - public void setIsLongpressEnabled(boolean enabled) { - mTapGestureDetector.setIsLongpressEnabled(enabled); - } - - /** - * Sets the image controller. - */ - @Override - public void setController(@Nullable DraweeController controller) { - setControllers(controller, null); - } - - /** - * Sets the controllers for the normal and huge image. - * - *

The huge image controller is used after the image gets scaled above a certain threshold. - * - *

IMPORTANT: in order to avoid a flicker when switching to the huge image, the huge image - * controller should have the normal-image-uri set as its low-res-uri. - * - * @param controller controller to be initially used - * @param hugeImageController controller to be used after the client starts zooming-in - */ - public void setControllers( - @Nullable DraweeController controller, - @Nullable DraweeController hugeImageController) { - setControllersInternal(null, null); - mZoomableController.setEnabled(false); - setControllersInternal(controller, hugeImageController); - } - - private void setControllersInternal( - @Nullable DraweeController controller, - @Nullable DraweeController hugeImageController) { - removeControllerListener(getController()); - addControllerListener(controller); - mHugeImageController = hugeImageController; - super.setController(controller); - } - - private void maybeSetHugeImageController() { - if (mHugeImageController != null && - mZoomableController.getScaleFactor() > HUGE_IMAGE_SCALE_FACTOR_THRESHOLD) { - setControllersInternal(mHugeImageController, null); - } - } - - private void removeControllerListener(DraweeController controller) { - if (controller instanceof AbstractDraweeController) { - ((AbstractDraweeController) controller) - .removeControllerListener(mControllerListener); - } - } - - private void addControllerListener(DraweeController controller) { - if (controller instanceof AbstractDraweeController) { - ((AbstractDraweeController) controller) - .addControllerListener(mControllerListener); - } - } - - @Override - protected void onDraw(Canvas canvas) { - int saveCount = canvas.save(); - canvas.concat(mZoomableController.getTransform()); - super.onDraw(canvas); - canvas.restoreToCount(saveCount); - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - int a = event.getActionMasked(); - FLog.v(getLogTag(), "onTouchEvent: %d, view %x, received", a, this.hashCode()); - if (mTapGestureDetector.onTouchEvent(event)) { - FLog.v( - getLogTag(), - "onTouchEvent: %d, view %x, handled by tap gesture detector", - a, - this.hashCode()); - return true; - } - if (mZoomableController.onTouchEvent(event)) { - if (!mZoomableController.isIdentity()) { - getParent().requestDisallowInterceptTouchEvent(true); - } - FLog.v( - getLogTag(), - "onTouchEvent: %d, view %x, handled by zoomable controller", - a, - this.hashCode()); - return true; - } - if (super.onTouchEvent(event)) { - FLog.v(getLogTag(), "onTouchEvent: %d, view %x, handled by the super", a, this.hashCode()); - return true; - } - // None of our components reported that they handled the touch event. Upon returning false - // from this method, our parent won't send us any more events for this gesture. Unfortunately, - // some componentes may have started a delayed action, such as a long-press timer, and since we - // won't receive an ACTION_UP that would cancel that timer, a false event may be triggered. - // To prevent that we explicitly send one last cancel event when returning false. - MotionEvent cancelEvent = MotionEvent.obtain(event); - cancelEvent.setAction(MotionEvent.ACTION_CANCEL); - mTapGestureDetector.onTouchEvent(cancelEvent); - mZoomableController.onTouchEvent(cancelEvent); - cancelEvent.recycle(); - return false; - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - FLog.v(getLogTag(), "onLayout: view %x", this.hashCode()); - super.onLayout(changed, left, top, right, bottom); - updateZoomableControllerBounds(); - } - - private void onFinalImageSet() { - FLog.v(getLogTag(), "onFinalImageSet: view %x", this.hashCode()); - if (!mZoomableController.isEnabled()) { - updateZoomableControllerBounds(); - mZoomableController.setEnabled(true); - } - } - - private void onRelease() { - FLog.v(getLogTag(), "onRelease: view %x", this.hashCode()); - mZoomableController.setEnabled(false); - } - - protected void onTransformChanged(Matrix transform) { - FLog.v(getLogTag(), "onTransformChanged: view %x, transform: %s", this.hashCode(), transform); - maybeSetHugeImageController(); - invalidate(); - } - - protected void updateZoomableControllerBounds() { - getImageBounds(mImageBounds); - getLimitBounds(mViewBounds); - mZoomableController.setImageBounds(mImageBounds); - mZoomableController.setViewBounds(mViewBounds); - FLog.v( - getLogTag(), - "updateZoomableControllerBounds: view %x, view bounds: %s, image bounds: %s", - this.hashCode(), - mViewBounds, - mImageBounds); - } - - protected Class getLogTag() { - return TAG; - } - - protected ZoomableController createZoomableController() { - return AnimatedZoomableController.newInstance(); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/ZoomableDraweeViewSupport.java b/app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/ZoomableDraweeViewSupport.java deleted file mode 100644 index 08c766aa..00000000 --- a/app/src/main/java/com/hiroshi/cimoc/ui/custom/zoomable/ZoomableDraweeViewSupport.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * This file provided by Facebook is for non-commercial testing and evaluation - * purposes only. Facebook reserves all rights not expressly granted. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -package com.hiroshi.cimoc.ui.custom.zoomable; - -import android.content.Context; -import android.util.AttributeSet; -import com.facebook.drawee.generic.GenericDraweeHierarchy; - -/** - * DraweeView that has zoomable capabilities. - *

- * Once the image loads, pinch-to-zoom and translation gestures are enabled. - */ -public class ZoomableDraweeViewSupport extends ZoomableDraweeView { - - private static final Class TAG = ZoomableDraweeViewSupport.class; - - public ZoomableDraweeViewSupport(Context context, GenericDraweeHierarchy hierarchy) { - super(context, hierarchy); - } - - public ZoomableDraweeViewSupport(Context context) { - super(context); - } - - public ZoomableDraweeViewSupport(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public ZoomableDraweeViewSupport(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - @Override - protected Class getLogTag() { - return TAG; - } - - @Override - protected ZoomableController createZoomableController() { - return AnimatedZoomableControllerSupport.newInstance(); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/hiroshi/cimoc/utils/ExLog.java b/app/src/main/java/com/hiroshi/cimoc/utils/ExLog.java index 16641c1c..58691e79 100644 --- a/app/src/main/java/com/hiroshi/cimoc/utils/ExLog.java +++ b/app/src/main/java/com/hiroshi/cimoc/utils/ExLog.java @@ -7,14 +7,10 @@ */ public class ExLog { - private static boolean flag = false; - - public static void enable() { - flag = true; - } + private static boolean DEBUG = true; public static void d(String tag, String msg) { - if (flag) { + if (DEBUG) { Log.d("ExLog", tag + " - " + msg); } } diff --git a/app/src/main/res/layout/item_picture.xml b/app/src/main/res/layout/item_picture.xml index 180455b5..1128dd24 100644 --- a/app/src/main/res/layout/item_picture.xml +++ b/app/src/main/res/layout/item_picture.xml @@ -1,5 +1,5 @@ - Date: Thu, 4 Aug 2016 23:54:09 +0800 Subject: [PATCH 002/521] =?UTF-8?q?=E5=AE=8C=E6=88=90=E6=A3=80=E6=9F=A5?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=8A=9F=E8=83=BD=20=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E9=A6=96=E9=A1=B5=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 2 +- .../com/hiroshi/cimoc/CimocApplication.java | 13 +-- .../java/com/hiroshi/cimoc/core/CCTuku.java | 27 +++-- .../com/hiroshi/cimoc/core/ComicManager.java | 56 +++++++++ .../java/com/hiroshi/cimoc/core/Dmzj.java | 18 ++- .../java/com/hiroshi/cimoc/core/EHentai.java | 13 ++- .../java/com/hiroshi/cimoc/core/HHAAZZ.java | 20 +++- .../java/com/hiroshi/cimoc/core/IKanman.java | 12 ++ .../java/com/hiroshi/cimoc/core/Kami.java | 27 ++++- .../com/hiroshi/cimoc/core/base/Manga.java | 33 +++++- .../com/hiroshi/cimoc/model/MiniComic.java | 11 ++ .../cimoc/presenter/FavoritePresenter.java | 18 ++- .../cimoc/presenter/HistoryPresenter.java | 7 +- .../cimoc/presenter/MainPresenter.java | 43 +++++-- .../cimoc/presenter/SettingsPresenter.java | 57 ++++----- .../cimoc/ui/activity/MainActivity.java | 7 +- .../cimoc/ui/adapter/ComicAdapter.java | 6 + .../cimoc/ui/fragment/AboutFragment.java | 5 +- .../cimoc/ui/fragment/CimocFragment.java | 12 +- .../cimoc/ui/fragment/FavoriteFragment.java | 110 +++++++++++++++++- .../cimoc/ui/fragment/HistoryFragment.java | 22 +++- .../cimoc/ui/fragment/SettingsFragment.java | 106 ++++++++++++----- .../hiroshi/cimoc/utils/DialogFactory.java | 39 +++++++ .../hiroshi/cimoc/utils/PreferenceMaster.java | 69 +++++++++++ .../res/drawable-hdpi/ic_sync_white_24dp.png | Bin 0 -> 387 bytes .../res/drawable-xhdpi/ic_sync_white_24dp.png | Bin 0 -> 494 bytes .../drawable-xxhdpi/ic_sync_white_24dp.png | Bin 0 -> 734 bytes app/src/main/res/layout/fragment_favorite.xml | 25 +++- app/src/main/res/layout/fragment_settings.xml | 22 ++++ app/src/main/res/layout/item_comic.xml | 11 ++ app/src/main/res/menu/drawer_menu.xml | 4 +- app/src/main/res/values/arrays.xml | 5 + app/src/main/res/values/strings.xml | 5 +- 33 files changed, 654 insertions(+), 151 deletions(-) create mode 100644 app/src/main/java/com/hiroshi/cimoc/utils/DialogFactory.java create mode 100644 app/src/main/java/com/hiroshi/cimoc/utils/PreferenceMaster.java create mode 100644 app/src/main/res/drawable-hdpi/ic_sync_white_24dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_sync_white_24dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_sync_white_24dp.png diff --git a/app/build.gradle b/app/build.gradle index 198ced10..c5615c38 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,7 +11,7 @@ android { minSdkVersion 15 targetSdkVersion 23 versionCode 1 - versionName "1.0.0" + versionName "1.1.0" resConfigs "en", "zh" } buildTypes { diff --git a/app/src/main/java/com/hiroshi/cimoc/CimocApplication.java b/app/src/main/java/com/hiroshi/cimoc/CimocApplication.java index 9d1659a7..6f8a5989 100644 --- a/app/src/main/java/com/hiroshi/cimoc/CimocApplication.java +++ b/app/src/main/java/com/hiroshi/cimoc/CimocApplication.java @@ -1,13 +1,12 @@ package com.hiroshi.cimoc; import android.app.Application; -import android.content.Context; -import android.content.SharedPreferences; import com.facebook.drawee.backends.pipeline.Fresco; import com.hiroshi.cimoc.model.DaoMaster; import com.hiroshi.cimoc.model.DaoMaster.DevOpenHelper; import com.hiroshi.cimoc.model.DaoSession; +import com.hiroshi.cimoc.utils.PreferenceMaster; import org.greenrobot.greendao.database.Database; @@ -18,19 +17,15 @@ */ public class CimocApplication extends Application { - public static final String PREF_EX = "pref_ex"; - - private static final String PREFERENCES_NAME = "cimoc_preferences"; - private static DaoSession daoSession; private static OkHttpClient httpClient; - private static SharedPreferences preferences; + private static PreferenceMaster preferences; @Override public void onCreate() { super.onCreate(); initDatabase(); - preferences = getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE); + preferences = new PreferenceMaster(getApplicationContext()); Fresco.initialize(this); } @@ -44,7 +39,7 @@ public static DaoSession getDaoSession() { return daoSession; } - public static SharedPreferences getPreferences() { + public static PreferenceMaster getPreferences() { return preferences; } diff --git a/app/src/main/java/com/hiroshi/cimoc/core/CCTuku.java b/app/src/main/java/com/hiroshi/cimoc/core/CCTuku.java index 0542443d..95cd6217 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/CCTuku.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/CCTuku.java @@ -5,6 +5,7 @@ import com.hiroshi.cimoc.model.Comic; import com.hiroshi.cimoc.utils.Decryption; import com.hiroshi.cimoc.utils.MachiSoup; +import com.hiroshi.cimoc.utils.MachiSoup.Node; import java.util.LinkedList; import java.util.List; @@ -29,9 +30,9 @@ protected Request buildSearchRequest(String keyword, int page) { @Override protected List parseSearch(String html) { - MachiSoup.Node body = MachiSoup.body(html); + Node body = MachiSoup.body(html); List list = new LinkedList<>(); - for (MachiSoup.Node node : body.list(".main-list > div > div > div")) { + for (Node node : body.list(".main-list > div > div > div")) { String cid = node.attr("div:eq(1) > div:eq(0) > a", "href", "/", 2); String title = node.text("div:eq(1) > div:eq(0) > a"); String cover = node.attr("div:eq(0) > a > img", "src"); @@ -51,18 +52,18 @@ protected Request buildIntoRequest(String cid) { @Override protected List parseInto(String html, Comic comic) { List list = new LinkedList<>(); - MachiSoup.Node body = MachiSoup.body(html); - for (MachiSoup.Node node : body.list("ul.list-body > li > a")) { + Node body = MachiSoup.body(html); + for (Node node : body.list("ul.list-body > li > a")) { String c_title = node.text(); String c_path = node.attr("href", "/", 3); list.add(new Chapter(c_title, c_path)); } String title = body.text("div.title-banner > div.book-title > h1", 0, -2); - MachiSoup.Node detail = body.select("div.book > div > div:eq(0)"); + Node detail = body.select("div.book > div > div:eq(0)"); String cover = detail.attr("div:eq(0) > a > img", "src"); - String update = detail.text("div:eq(0) > dl:eq(5) > dd > font", 0, 10); - String author = detail.text("div:eq(0) > dl:eq(1) > dd > a"); + String update = detail.text("div:eq(1) > div > dl:eq(5) > dd > font", 0, 10); + String author = detail.text("div:eq(1) > div > dl:eq(1) > dd > a"); String intro = body.text("div.book-details > p:eq(1)"); boolean status = "完结".equals(detail.text("div:eq(0) > div")); comic.setInfo(title, cover, update, intro, author, status); @@ -100,4 +101,16 @@ protected String[] parseBrowse(String html) { return null; } + @Override + protected Request buildCheckRequest(String cid) { + String url = host + "/comic/" + cid; + return new Request.Builder().url(url).build(); + } + + @Override + protected String parseCheck(String html) { + Node body = MachiSoup.body(html); + return body.text("div.book > div > div:eq(0) > div:eq(1) > div > dl:eq(5) > dd > font", 0, 10); + } + } diff --git a/app/src/main/java/com/hiroshi/cimoc/core/ComicManager.java b/app/src/main/java/com/hiroshi/cimoc/core/ComicManager.java index ee6bcab1..2b982229 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/ComicManager.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/ComicManager.java @@ -21,6 +21,8 @@ */ public class ComicManager { + public static final long NEW_VALUE = 0xFFFFFFFFFFFL; + private static ComicManager mComicManager; private ComicDao mComicDao; @@ -57,6 +59,42 @@ public void run() { }); } + public void updateFavorite(final List list) { + mComicDao.getSession().runInTx(new Runnable() { + @Override + public void run() { + for (MiniComic comic : list) { + Comic temp = mComicDao.load(comic.getId()); + if (temp != null) { + temp.setUpdate(comic.getUpdate()); + temp.setFavorite(NEW_VALUE); + mComicDao.update(temp); + } + } + } + }); + } + + public void removeFavorite(long id) { + Comic comic = mComicDao.load(id); + if (comic.getHistory() == null) { + mComicDao.delete(comic); + } else { + comic.setFavorite(null); + mComicDao.update(comic); + } + } + + public void removeHistory(long id) { + Comic comic = mComicDao.load(id); + if (comic.getFavorite() == null) { + mComicDao.delete(comic); + } else { + comic.setHistory(null); + mComicDao.update(comic); + } + } + public void cleanHistory() { mComicDao.getSession().runInTx(new Runnable() { @Override @@ -79,6 +117,24 @@ public List listBackup() { return mComicDao.queryBuilder().where(Properties.Favorite.isNotNull()).list(); } + public MiniComic[] arrayFavorite() { + Cursor cursor = mComicDao.queryBuilder() + .where(ComicDao.Properties.Favorite.isNotNull()) + .buildCursor() + .query(); + MiniComic[] array = new MiniComic[cursor.getCount()]; + int count = 0; + while (cursor.moveToNext()) { + long id = cursor.getLong(0); + int source = cursor.getInt(1); + String cid = cursor.getString(2); + String update = cursor.getString(5); + array[count++] = new MiniComic(id, source, cid, null, null, update); + } + cursor.close(); + return array; + } + public List listFavorite() { Cursor cursor = mComicDao.queryBuilder() .where(ComicDao.Properties.Favorite.isNotNull()) diff --git a/app/src/main/java/com/hiroshi/cimoc/core/Dmzj.java b/app/src/main/java/com/hiroshi/cimoc/core/Dmzj.java index d2e236da..547df5e4 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/Dmzj.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/Dmzj.java @@ -87,9 +87,9 @@ protected List parseInto(String html, Comic comic) { } } - Node doc = MachiSoup.body(html); - String intro = doc.text(".txtDesc", 3); - Node detail = doc.select(".Introduct_Sub"); + Node body = MachiSoup.body(html); + String intro = body.text(".txtDesc", 3); + Node detail = body.select(".Introduct_Sub"); String title = detail.attr("#Cover > img", "title"); String cover = detail.attr("#Cover > img", "src"); String author = detail.text(".sub_r > p:eq(0) > a"); @@ -124,4 +124,16 @@ protected String[] parseBrowse(String html) { return null; } + @Override + protected Request buildCheckRequest(String cid) { + String url = host + "/info/" + cid + ".html"; + return new Request.Builder().url(url).build(); + } + + @Override + protected String parseCheck(String html) { + Node doc = MachiSoup.body(html); + return doc.text(".Introduct_Sub > .sub_r > p:eq(3) > .date", " ", 0); + } + } diff --git a/app/src/main/java/com/hiroshi/cimoc/core/EHentai.java b/app/src/main/java/com/hiroshi/cimoc/core/EHentai.java index a05e5113..38e8594e 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/EHentai.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/EHentai.java @@ -82,7 +82,8 @@ protected String[] parseBrowse(String html) { String[] array = new String[list.size()]; for (int i = 0; i != list.size(); ++i) { String url = list.get(i).attr("href"); - String result = execute(url); + Request request = new Request.Builder().url(url).build(); + String result = execute(request); if (result != null) { Node node = MachiSoup.body(result); array[i] = node.attr("#sm", "src"); @@ -93,4 +94,14 @@ protected String[] parseBrowse(String html) { return array; } + @Override + protected Request buildCheckRequest(String cid) { + return null; + } + + @Override + protected String parseCheck(String html) { + return null; + } + } diff --git a/app/src/main/java/com/hiroshi/cimoc/core/HHAAZZ.java b/app/src/main/java/com/hiroshi/cimoc/core/HHAAZZ.java index 99774632..923e6d3c 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/HHAAZZ.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/HHAAZZ.java @@ -56,20 +56,20 @@ protected Request buildIntoRequest(String cid) { @Override protected List parseInto(String html, Comic comic) { List list = new LinkedList<>(); - Node doc = MachiSoup.body(html); - List nodes = doc.list("#sort_div_p > a"); + Node body = MachiSoup.body(html); + List nodes = body.list("#sort_div_p > a"); for (Node node : nodes) { String c_title = node.attr("title"); String c_path = node.attr("href").substring(host.length()); list.add(new Chapter(c_title, c_path)); } - Node detail = doc.select(".main > div > div.pic"); + Node detail = body.select(".main > div > div.pic"); String title = detail.text("div:eq(1) > h3"); String cover = detail.attr("img:eq(0)", "src"); String update = detail.text("div:eq(1) > p:eq(5)", 5); String author = detail.text("div:eq(1) > p:eq(1)", 3); - String intro = doc.text("#detail_block > div > p"); + String intro = body.text("#detail_block > div > p"); boolean status = detail.text("div:eq(1) > p:eq(4)").contains("完结"); comic.setInfo(title, cover, update, intro, author, status); @@ -113,4 +113,16 @@ private static String[] unsuan(String str) { return builder.toString().split("\\|"); } + @Override + protected Request buildCheckRequest(String cid) { + String url = host + "/comic/" + cid; + return new Request.Builder().url(url).build(); + } + + @Override + protected String parseCheck(String html) { + Node body = MachiSoup.body(html); + return body.text(".main > div > div.pic > div:eq(1) > p:eq(5)", 5); + } + } diff --git a/app/src/main/java/com/hiroshi/cimoc/core/IKanman.java b/app/src/main/java/com/hiroshi/cimoc/core/IKanman.java index e771d0d9..d2bedc60 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/IKanman.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/IKanman.java @@ -106,4 +106,16 @@ protected String[] parseBrowse(String html) { return null; } + @Override + protected Request buildCheckRequest(String cid) { + String url = host + "/comic/" + cid; + return new Request.Builder().url(url).build(); + } + + @Override + protected String parseCheck(String html) { + Node body = MachiSoup.body(html); + return body.text("div.book-detail > div:eq(0) > dl:eq(2) > dd"); + } + } diff --git a/app/src/main/java/com/hiroshi/cimoc/core/Kami.java b/app/src/main/java/com/hiroshi/cimoc/core/Kami.java index b866c5c1..63cc6bb2 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/Kami.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/Kami.java @@ -45,19 +45,36 @@ public static String getRefererById(int id) { } } + private static Manga mIkanman, mDmzj, mHHAAZZ, mCCTuku, mEHentai; + public static Manga getMangaById(int id) { switch (id) { default: case SOURCE_IKANMAN: - return new IKanman(); + if (mIkanman == null) { + mIkanman = new IKanman(); + } + return mIkanman; case SOURCE_DMZJ: - return new Dmzj(); + if (mDmzj == null) { + mDmzj = new Dmzj(); + } + return mDmzj; case SOURCE_HHAAZZ: - return new HHAAZZ(); + if (mHHAAZZ == null) { + mHHAAZZ = new HHAAZZ(); + } + return mHHAAZZ; case SOURCE_CCTUKU: - return new CCTuku(); + if (mCCTuku == null) { + mCCTuku = new CCTuku(); + } + return mCCTuku; case SOURCE_EHENTAI: - return new EHentai(); + if (mEHentai == null) { + mEHentai = new EHentai(); + } + return mEHentai; } } diff --git a/app/src/main/java/com/hiroshi/cimoc/core/base/Manga.java b/app/src/main/java/com/hiroshi/cimoc/core/base/Manga.java index d18f843a..01e1fa4d 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/base/Manga.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/base/Manga.java @@ -9,6 +9,7 @@ import java.io.IOException; import java.util.List; +import java.util.concurrent.TimeUnit; import okhttp3.Call; import okhttp3.Callback; @@ -21,7 +22,7 @@ */ public abstract class Manga { - private OkHttpClient client; + private OkHttpClient mClient; protected int source; protected String host; @@ -29,7 +30,7 @@ public abstract class Manga { public Manga(int source, String host) { this.source = source; this.host = host; - this.client = CimocApplication.getHttpClient(); + this.mClient = CimocApplication.getHttpClient(); } public void search(String keyword, int page) { @@ -79,16 +80,29 @@ public void onSuccess(String html) { }); } + public String check(String cid) { + OkHttpClient client = new OkHttpClient.Builder() + .connectTimeout(500, TimeUnit.MILLISECONDS) + .readTimeout(1000, TimeUnit.MILLISECONDS) + .build(); + String html = execute(client, buildCheckRequest(cid)); + if (html != null) { + return parseCheck(html); + } + return null; + } + public void cancel() { - client.dispatcher().cancelAll(); + mClient.dispatcher().cancelAll(); } private void enqueueClient(Request request, final OnResponseSuccessHandler handler) { - client.newCall(request).enqueue(new Callback() { + mClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { EventBus.getDefault().post(new EventMessage(EventMessage.NETWORK_ERROR, null)); } + @Override public void onResponse(Call call, Response response) throws IOException { if (response.isSuccessful()) { @@ -100,8 +114,7 @@ public void onResponse(Call call, Response response) throws IOException { }); } - protected String execute(String url) { - Request request = new Request.Builder().url(url).build(); + private String execute(OkHttpClient client, Request request) { try { Response response = client.newCall(request).execute(); if (response.isSuccessful()) { @@ -113,6 +126,10 @@ protected String execute(String url) { return null; } + protected String execute(Request request) { + return execute(mClient, request); + } + protected abstract Request buildSearchRequest(String keyword, int page); protected abstract List parseSearch(String html); @@ -125,6 +142,10 @@ protected String execute(String url) { protected abstract String[] parseBrowse(String html); + protected abstract Request buildCheckRequest(String cid); + + protected abstract String parseCheck(String html); + private interface OnResponseSuccessHandler { void onSuccess(String html); } diff --git a/app/src/main/java/com/hiroshi/cimoc/model/MiniComic.java b/app/src/main/java/com/hiroshi/cimoc/model/MiniComic.java index 05fb7030..492c1aab 100644 --- a/app/src/main/java/com/hiroshi/cimoc/model/MiniComic.java +++ b/app/src/main/java/com/hiroshi/cimoc/model/MiniComic.java @@ -11,6 +11,7 @@ public class MiniComic { private String title; private String cover; private String update; + private boolean status; public MiniComic(Long id, int source, String cid, String title, String cover, String update) { this.id = id; @@ -19,6 +20,7 @@ public MiniComic(Long id, int source, String cid, String title, String cover, St this.title = title; this.cover = cover; this.update = update; + this.status = false; } public MiniComic(Comic comic) { @@ -28,6 +30,7 @@ public MiniComic(Comic comic) { this.title = comic.getTitle(); this.cover = comic.getCover(); this.update = comic.getUpdate(); + this.status = false; } @Override @@ -35,6 +38,14 @@ public boolean equals(Object o) { return o instanceof MiniComic && ((MiniComic) o).id.equals(id); } + public boolean getStatus() { + return this.status; + } + + public void setStatus(boolean status) { + this.status = status; + } + public String getUpdate() { return this.update; } diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/FavoritePresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/FavoritePresenter.java index 03f3d1cd..07de244e 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/FavoritePresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/FavoritePresenter.java @@ -26,16 +26,28 @@ public FavoritePresenter(FavoriteFragment fragment) { mComicManager = ComicManager.getInstance(); } - public List getComic() { + public List getComicList() { return mComicManager.listFavorite(); } - public void onItemClick(int position) { - MiniComic comic = mFavoriteFragment.getItem(position); + public MiniComic[] getComicArray() { + return mComicManager.arrayFavorite(); + } + + public void onItemClick(MiniComic comic) { Intent intent = DetailActivity.createIntent(mFavoriteFragment.getActivity(), comic.getId(), comic.getSource(), comic.getCid()); mFavoriteFragment.startActivity(intent); } + public void updateComic(List list) { + mComicManager.updateFavorite(list); + } + + public void onPositiveClick(MiniComic comic) { + mComicManager.removeFavorite(comic.getId()); + } + + @SuppressWarnings("unchecked") @Subscribe(threadMode = ThreadMode.MAIN) public void onEvent(EventMessage msg) { switch (msg.getType()) { diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/HistoryPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/HistoryPresenter.java index c1eaaf02..5e45c6f5 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/HistoryPresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/HistoryPresenter.java @@ -30,12 +30,15 @@ public List getComic() { return mComicManager.listHistory(); } - public void onItemClick(int position) { - MiniComic comic = mHistoryFragment.getItem(position); + public void onItemClick(MiniComic comic) { Intent intent = DetailActivity.createIntent(mHistoryFragment.getActivity(), comic.getId(), comic.getSource(), comic.getCid()); mHistoryFragment.startActivity(intent); } + public void onPositiveClick(MiniComic comic) { + mComicManager.removeHistory(comic.getId()); + } + @Subscribe(threadMode = ThreadMode.MAIN) public void onEvent(EventMessage msg) { switch (msg.getType()) { diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/MainPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/MainPresenter.java index 9bfd8739..2516e2f7 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/MainPresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/MainPresenter.java @@ -12,6 +12,7 @@ import com.hiroshi.cimoc.ui.fragment.HistoryFragment; import com.hiroshi.cimoc.model.EventMessage; import com.hiroshi.cimoc.ui.fragment.SettingsFragment; +import com.hiroshi.cimoc.utils.PreferenceMaster; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; @@ -33,33 +34,51 @@ public class MainPresenter extends BasePresenter { private AboutFragment mAboutFragment; private Fragment mCurrentFragment; - public MainPresenter(MainActivity activity) { + public MainPresenter(MainActivity activity, int item) { mMainActivity = activity; + mCheckedItem = item; mExitTime = 0; initFragment(); } - private void initFragment() { - mFragmentManager = mMainActivity.getFragmentManager(); - mCimocFragment = new CimocFragment(); - mFavoriteFragment = new FavoriteFragment(); - mHistoryFragment = new HistoryFragment(); - mSettingsFragment = new SettingsFragment(); - mAboutFragment = new AboutFragment(); + @Override + public void onCreate() { + super.onCreate(); + switch (mCheckedItem) { + case R.id.drawer_cimoc: + mCurrentFragment = mCimocFragment; + break; + case R.id.drawer_favorite: + mCurrentFragment = mFavoriteFragment; + break; + case R.id.drawer_history: + mCurrentFragment = mHistoryFragment; + break; + } mFragmentManager.beginTransaction() .add(R.id.main_fragment_container, mCimocFragment) .add(R.id.main_fragment_container, mFavoriteFragment) .add(R.id.main_fragment_container, mHistoryFragment) .add(R.id.main_fragment_container, mSettingsFragment) .add(R.id.main_fragment_container, mAboutFragment) + .hide(mCimocFragment) .hide(mFavoriteFragment) .hide(mHistoryFragment) .hide(mSettingsFragment) .hide(mAboutFragment) + .show(mCurrentFragment) .commit(); - mCurrentFragment = mCimocFragment; - mCheckedItem = R.id.drawer_main; mMainActivity.setCheckedItem(mCheckedItem); + mMainActivity.setTitle(PreferenceMaster.getTitleById(mCheckedItem)); + } + + private void initFragment() { + mFragmentManager = mMainActivity.getFragmentManager(); + mCimocFragment = new CimocFragment(); + mFavoriteFragment = new FavoriteFragment(); + mHistoryFragment = new HistoryFragment(); + mSettingsFragment = new SettingsFragment(); + mAboutFragment = new AboutFragment(); } public void onBackPressed() { @@ -76,10 +95,10 @@ public void onBackPressed() { public void transFragment() { switch (mCheckedItem) { default: - case R.id.drawer_main: + case R.id.drawer_cimoc: mCurrentFragment = mCimocFragment; break; - case R.id.drawer_comic: + case R.id.drawer_favorite: mCurrentFragment = mFavoriteFragment; break; case R.id.drawer_history: diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/SettingsPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/SettingsPresenter.java index eae2fdb0..54b3ba5b 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/SettingsPresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/SettingsPresenter.java @@ -1,9 +1,5 @@ package com.hiroshi.cimoc.presenter; -import android.content.DialogInterface; -import android.support.v7.app.AlertDialog; - -import com.hiroshi.cimoc.R; import com.hiroshi.cimoc.core.ComicManager; import com.hiroshi.cimoc.model.Comic; import com.hiroshi.cimoc.model.EventMessage; @@ -29,53 +25,40 @@ public SettingsPresenter(SettingsFragment fragment) { mComicManager = ComicManager.getInstance(); } - public void cleanCache() { - mSettingsFragment.showAlertDialog("正在删除.."); + public void onCacheBtnClick() { + mSettingsFragment.showProgressDialog("正在删除.."); FileUtils.deleteDir(mSettingsFragment.getActivity().getCacheDir()); mSettingsFragment.showSnackbar("删除成功"); - mSettingsFragment.hideAlertDialog(); + mSettingsFragment.hideProgressDialog(); } - public void backupComic() { - mSettingsFragment.showAlertDialog("正在备份.."); + public void onBackupBtnClick() { + mSettingsFragment.showProgressDialog("正在备份.."); List list = mComicManager.listBackup(); if (BackupUtils.saveComic(list)) { mSettingsFragment.showSnackbar("备份成功 共 " + list.size() + " 条记录"); } else { mSettingsFragment.showSnackbar("备份失败 共 " + list.size() + " 条记录"); } - mSettingsFragment.hideAlertDialog(); + mSettingsFragment.hideProgressDialog(); } - private int choice; - - public void restoreComic() { - final String[] files = BackupUtils.showBackupFiles(); + public String[] getFiles() { + String[] files = BackupUtils.showBackupFiles(); if (files == null || files.length == 0) { - mSettingsFragment.showSnackbar("没有找到备份文件"); - return; + return null; } - AlertDialog.Builder builder = new AlertDialog.Builder(mSettingsFragment.getActivity(), R.style.AppTheme_Dialog_Alert); - builder.setTitle("选择文件"); - builder.setSingleChoiceItems(files, -1, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - choice = which; - } - }); - builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - mSettingsFragment.showAlertDialog("正在恢复.."); - List list = BackupUtils.restoreComic(files[choice]); - mComicManager.restoreFavorite(list); - } - }); - builder.show(); + return files; + } + + public void onRestorePositiveBtnClick(String name) { + mSettingsFragment.showProgressDialog("正在恢复.."); + List list = BackupUtils.restoreComic(name); + mComicManager.restoreFavorite(list); } - public void cleanHistory() { - mSettingsFragment.showAlertDialog("正在删除.."); + public void onHistoryBtnClick() { + mSettingsFragment.showProgressDialog("正在删除.."); mComicManager.cleanHistory(); } @@ -84,12 +67,12 @@ public void onEvent(EventMessage msg) { switch (msg.getType()) { case EventMessage.DELETE_HISTORY: int count = (int) msg.getData(); - mSettingsFragment.hideAlertDialog(); + mSettingsFragment.hideProgressDialog(); mSettingsFragment.showSnackbar("删除成功 共 " + count + " 条记录"); break; case EventMessage.RESTORE_FAVORITE: List list = (List) msg.getData(); - mSettingsFragment.hideAlertDialog(); + mSettingsFragment.hideProgressDialog(); mSettingsFragment.showSnackbar("恢复成功 共 " + list.size() + " 条记录"); break; } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/MainActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/MainActivity.java index 6f6fa07c..8306c2d8 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/MainActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/MainActivity.java @@ -10,9 +10,11 @@ import android.widget.FrameLayout; import android.widget.ProgressBar; +import com.hiroshi.cimoc.CimocApplication; import com.hiroshi.cimoc.R; import com.hiroshi.cimoc.presenter.BasePresenter; import com.hiroshi.cimoc.presenter.MainPresenter; +import com.hiroshi.cimoc.utils.PreferenceMaster; import butterknife.BindView; @@ -30,7 +32,8 @@ public class MainActivity extends BaseActivity { @Override protected void initPresenter() { - mPresenter = new MainPresenter(this); + int item = CimocApplication.getPreferences().getInt(PreferenceMaster.PREF_HOME, R.id.drawer_cimoc); + mPresenter = new MainPresenter(this, item); } @Override @@ -64,7 +67,7 @@ protected int getLayoutView() { @Override protected String getDefaultTitle() { - return "Cimoc"; + return null; } @Override diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ComicAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ComicAdapter.java index 317578a3..88b54390 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ComicAdapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ComicAdapter.java @@ -27,6 +27,7 @@ public class ViewHolder extends BaseViewHolder { @BindView(R.id.item_comic_image) SimpleDraweeView comicImage; @BindView(R.id.item_comic_title) TextView comicTitle; @BindView(R.id.item_comic_source) TextView comicSource; + @BindView(R.id.item_comic_new) TextView comicNew; public ViewHolder(View view) { super(view); @@ -51,6 +52,11 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { viewHolder.comicSource.setText(Kami.getSourceById(comic.getSource())); PipelineDraweeControllerBuilder builder = ControllerBuilderFactory.getControllerBuilder(comic.getSource(), mContext); viewHolder.comicImage.setController(builder.setUri(comic.getCover()).build()); + if (comic.getStatus()) { + viewHolder.comicNew.setVisibility(View.VISIBLE); + } else { + viewHolder.comicNew.setVisibility(View.INVISIBLE); + } } @Override diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/AboutFragment.java b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/AboutFragment.java index 696414f2..3685aae8 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/AboutFragment.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/AboutFragment.java @@ -5,6 +5,7 @@ import com.hiroshi.cimoc.CimocApplication; import com.hiroshi.cimoc.R; import com.hiroshi.cimoc.presenter.BasePresenter; +import com.hiroshi.cimoc.utils.PreferenceMaster; import butterknife.OnClick; @@ -19,7 +20,7 @@ public class AboutFragment extends BaseFragment { @OnClick(R.id.about_resource_btn) void onClick() { if (++count > 9) { isEnable = !isEnable; - CimocApplication.getPreferences().edit().putBoolean(CimocApplication.PREF_EX, isEnable).apply(); + CimocApplication.getPreferences().putBoolean(PreferenceMaster.PREF_EX, isEnable); if (getView() != null) { String msg = isEnable ? "重启软件开启 EHentai" : "重启软件关闭 EHentai"; Snackbar.make(getView(), msg, Snackbar.LENGTH_SHORT).show(); @@ -33,7 +34,7 @@ protected void initPresenter() {} @Override protected void initView() { - isEnable = CimocApplication.getPreferences().getBoolean(CimocApplication.PREF_EX, false); + isEnable = CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_EX, false); count = 0; } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/CimocFragment.java b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/CimocFragment.java index 0d59ffdf..a2317ff1 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/CimocFragment.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/CimocFragment.java @@ -3,7 +3,6 @@ import android.content.DialogInterface; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.TextInputLayout; -import android.support.v7.app.AlertDialog; import android.text.Editable; import android.text.TextWatcher; import android.view.KeyEvent; @@ -16,6 +15,8 @@ import com.hiroshi.cimoc.core.Kami; import com.hiroshi.cimoc.presenter.BasePresenter; import com.hiroshi.cimoc.ui.activity.ResultActivity; +import com.hiroshi.cimoc.utils.DialogFactory; +import com.hiroshi.cimoc.utils.PreferenceMaster; import butterknife.BindView; import butterknife.OnClick; @@ -44,15 +45,12 @@ public class CimocFragment extends BaseFragment { } @OnLongClick(R.id.main_search_btn) boolean onLongClick() { - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), R.style.AppTheme_Dialog_Alert); - builder.setTitle("图源选择"); - builder.setSingleChoiceItems(array, choice, new DialogInterface.OnClickListener() { + DialogFactory.buildSingleChoiceDialog(getActivity(), "图源选择", array, choice, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { choice = which; } - }); - builder.show(); + }, null).show(); return true; } @@ -79,7 +77,7 @@ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { } }); choice = 0; - boolean enable = CimocApplication.getPreferences().getBoolean(CimocApplication.PREF_EX, false); + boolean enable = CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_EX, false); array = enable ? R.array.ex_source_items : R.array.source_items; if (enable) { source = new int[]{ Kami.SOURCE_IKANMAN, Kami.SOURCE_DMZJ, Kami.SOURCE_HHAAZZ, Kami.SOURCE_CCTUKU, Kami.SOURCE_EHENTAI }; diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/FavoriteFragment.java b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/FavoriteFragment.java index e2a4e82c..4b29127e 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/FavoriteFragment.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/FavoriteFragment.java @@ -1,19 +1,31 @@ package com.hiroshi.cimoc.ui.fragment; +import android.app.Notification; +import android.app.NotificationManager; +import android.content.Context; +import android.content.DialogInterface; +import android.os.AsyncTask; +import android.os.Build; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; +import android.util.Log; import android.view.View; import com.hiroshi.cimoc.R; +import com.hiroshi.cimoc.core.Kami; +import com.hiroshi.cimoc.core.base.Manga; import com.hiroshi.cimoc.model.MiniComic; import com.hiroshi.cimoc.presenter.BasePresenter; import com.hiroshi.cimoc.presenter.FavoritePresenter; import com.hiroshi.cimoc.ui.adapter.BaseAdapter; import com.hiroshi.cimoc.ui.adapter.ComicAdapter; +import com.hiroshi.cimoc.utils.DialogFactory; +import java.util.LinkedList; import java.util.List; import butterknife.BindView; +import butterknife.OnClick; /** * Created by Hiroshi on 2016/7/1. @@ -24,14 +36,33 @@ public class FavoriteFragment extends BaseFragment { private ComicAdapter mComicAdapter; private FavoritePresenter mPresenter; + private Notification.Builder mBuilder; + private NotificationManager mManager; + + private boolean isChecking; @Override protected void initView() { - mComicAdapter = new ComicAdapter(getActivity(), mPresenter.getComic()); + isChecking = false; + mManager = (NotificationManager) getActivity().getSystemService(Context.NOTIFICATION_SERVICE); + mBuilder = new Notification.Builder(getActivity()); + mComicAdapter = new ComicAdapter(getActivity(), mPresenter.getComicList()); mComicAdapter.setOnItemClickListener(new BaseAdapter.OnItemClickListener() { @Override public void onItemClick(View view, int position) { - mPresenter.onItemClick(position); + mPresenter.onItemClick(mComicAdapter.getItem(position)); + } + }); + mComicAdapter.setOnItemLongClickListener(new BaseAdapter.OnItemLongClickListener() { + @Override + public void onItemLongClick(View view, final int position) { + DialogFactory.buildPositiveDialog(getActivity(), "删除提示", "是否删除该收藏", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + mPresenter.onPositiveClick(mComicAdapter.getItem(position)); + mComicAdapter.remove(position); + } + }).show(); } }); mRecyclerView.setItemAnimator(null); @@ -40,6 +71,14 @@ public void onItemClick(View view, int position) { mRecyclerView.addItemDecoration(mComicAdapter.getItemDecoration()); } + @OnClick(R.id.favorite_check_btn) void onCheckClick() { + if (!isChecking) { + isChecking = true; + UpdateTask task = new UpdateTask(); + task.execute(mPresenter.getComicArray()); + } + } + @Override protected int getLayoutView() { return R.layout.fragment_favorite; @@ -55,10 +94,6 @@ protected void initPresenter() { mPresenter = new FavoritePresenter(this); } - public MiniComic getItem(int position) { - return mComicAdapter.getItem(position); - } - public void addItem(MiniComic comic) { mComicAdapter.add(0, comic); } @@ -71,6 +106,69 @@ public void addItems(List list) { mComicAdapter.addAll(0, list); } + class UpdateTask extends AsyncTask> { + @Override + protected void onPreExecute() { + mBuilder.setSmallIcon(R.drawable.ic_sync_white_24dp) + .setContentTitle("Cimoc") + .setContentText("正在检查更新") + .setTicker("正在检查更新") + .setOngoing(true) + .setProgress(0, 0, true); + if (Build.VERSION.SDK_INT >= 16) { + mManager.notify(1, mBuilder.build()); + } else { + mManager.notify(1, mBuilder.getNotification()); + } + } + + @Override + protected List doInBackground(MiniComic... params) { + List list = new LinkedList<>(); + int count = 1; + for (MiniComic comic : params) { + int source = comic.getSource(); + if (source == Kami.SOURCE_EHENTAI) { + continue; + } + Manga manga = Kami.getMangaById(source); + String update = manga.check(comic.getCid()); + if (update != null && !comic.getUpdate().equals(update)) { + comic.setUpdate(update); + list.add(comic); + } + publishProgress(count++, params.length); + } + return list; + } + + @Override + protected void onProgressUpdate(Integer... values) { + Log.e("----------", "------" + values[0] + "---" + values[1]); + mBuilder.setProgress(values[1], values[0], false) + .setTicker(null); + if (Build.VERSION.SDK_INT >= 16) { + mManager.notify(1, mBuilder.build()); + } else { + mManager.notify(1, mBuilder.getNotification()); + } + } + + @Override + protected void onPostExecute(List list) { + //mPresenter.updateComic(list); + mBuilder.setOngoing(false) + .setTicker(null) + .setContentText("检查完成") + .setProgress(0, 0, false); + if (Build.VERSION.SDK_INT >= 16) { + mManager.notify(1, mBuilder.build()); + } else { + mManager.notify(1, mBuilder.getNotification()); + } + isChecking = false; + } + } } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/HistoryFragment.java b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/HistoryFragment.java index d1354965..cb43df29 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/HistoryFragment.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/HistoryFragment.java @@ -1,5 +1,7 @@ package com.hiroshi.cimoc.ui.fragment; +import android.content.DialogInterface; +import android.support.v7.app.AlertDialog; import android.support.v7.widget.DefaultItemAnimator; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; @@ -11,6 +13,7 @@ import com.hiroshi.cimoc.presenter.HistoryPresenter; import com.hiroshi.cimoc.ui.adapter.BaseAdapter; import com.hiroshi.cimoc.ui.adapter.ComicAdapter; +import com.hiroshi.cimoc.utils.DialogFactory; import butterknife.BindView; @@ -30,12 +33,23 @@ protected void initView() { mComicAdapter.setOnItemClickListener(new BaseAdapter.OnItemClickListener() { @Override public void onItemClick(View view, int position) { - mPresenter.onItemClick(position); + mPresenter.onItemClick(mComicAdapter.getItem(position)); + } + }); + mComicAdapter.setOnItemLongClickListener(new BaseAdapter.OnItemLongClickListener() { + @Override + public void onItemLongClick(View view, final int position) { + DialogFactory.buildPositiveDialog(getActivity(), "删除提示", "是否删除该历史纪录", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + mPresenter.onPositiveClick(mComicAdapter.getItem(position)); + mComicAdapter.remove(position); + } + }).show(); } }); mRecyclerView.setItemAnimator(null); mRecyclerView.setLayoutManager(new GridLayoutManager(getActivity(), 3)); - mRecyclerView.setItemAnimator(new DefaultItemAnimator()); mRecyclerView.setAdapter(mComicAdapter); mRecyclerView.addItemDecoration(mComicAdapter.getItemDecoration()); } @@ -55,10 +69,6 @@ protected int getLayoutView() { return R.layout.fragment_history; } - public MiniComic getItem(int position) { - return mComicAdapter.getItem(position); - } - public void updateItem(MiniComic comic) { mComicAdapter.update(comic); } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SettingsFragment.java b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SettingsFragment.java index ab335781..8d62eff5 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SettingsFragment.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SettingsFragment.java @@ -1,13 +1,19 @@ package com.hiroshi.cimoc.ui.fragment; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; import android.support.design.widget.Snackbar; import android.support.v7.app.AlertDialog; -import android.view.View; +import android.widget.TextView; +import com.hiroshi.cimoc.CimocApplication; import com.hiroshi.cimoc.R; import com.hiroshi.cimoc.presenter.BasePresenter; import com.hiroshi.cimoc.presenter.SettingsPresenter; +import com.hiroshi.cimoc.utils.DialogFactory; +import com.hiroshi.cimoc.utils.PreferenceMaster; +import butterknife.BindView; import butterknife.OnClick; /** @@ -15,31 +21,76 @@ */ public class SettingsFragment extends BaseFragment { + @BindView(R.id.settings_other_home_summary) TextView mIndexSummary; + private SettingsPresenter mPresenter; - private AlertDialog mAlertDialog; - - @OnClick({ R.id.settings_backup_save_btn, R.id.settings_backup_restore_btn, R.id.settings_other_history_btn, R.id.settings_other_cache_btn}) - void onClick(View view) { - switch (view.getId()) { - case R.id.settings_backup_save_btn: - mPresenter.backupComic(); - break; - case R.id.settings_backup_restore_btn: - mPresenter.restoreComic(); - break; - case R.id.settings_other_cache_btn: - mPresenter.cleanCache(); - break; - case R.id.settings_other_history_btn: - mPresenter.cleanHistory(); - break; + private AlertDialog mProgressDialog; + + private int mBackupChoice; + private int mHomeChoice; + + @Override + protected void initView() { + mProgressDialog = new AlertDialog.Builder(getActivity(), R.style.AppTheme_Dialog_Alert).setCancelable(false).create(); + mHomeChoice = CimocApplication.getPreferences().getInt(PreferenceMaster.PREF_HOME, R.id.drawer_cimoc); + mIndexSummary.setText(PreferenceMaster.getTitleById(mHomeChoice)); + } + + @OnClick(R.id.settings_backup_restore_btn) void onRestoreBtnClick() { + final String[] array = mPresenter.getFiles(); + if (array == null) { + showSnackbar("没有找到备份文件"); + return; } + DialogFactory.buildSingleChoiceDialog(getActivity(), "选择文件", array, -1, + new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + mBackupChoice = which; + } + }, + new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + mPresenter.onRestorePositiveBtnClick(array[mBackupChoice]); + } + }).show(); + } + + @OnClick(R.id.settings_other_home_btn) void onHomeBtnClick() { + final int[] array = new int[] { R.id.drawer_cimoc, R.id.drawer_favorite, R.id.drawer_history }; + DialogFactory.buildSingleChoiceDialog(getActivity(), "首页选择", R.array.index_items, -1, + new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + mHomeChoice = array[which]; + } + }, + new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + CimocApplication.getPreferences().putInt(PreferenceMaster.PREF_HOME, mHomeChoice); + mIndexSummary.setText(PreferenceMaster.getTitleById(mHomeChoice)); + } + }).show(); + } + + @OnClick(R.id.settings_backup_save_btn) void onSaveBtnClick() { + mPresenter.onBackupBtnClick(); + } + + @OnClick(R.id.settings_other_cache_btn) void onCacheBtnClick() { + mPresenter.onCacheBtnClick(); + } + + @OnClick(R.id.settings_other_history_btn) void onHistoryBtnClick() { + mPresenter.onHistoryBtnClick(); } @Override public void onDestroy() { super.onDestroy(); - mAlertDialog.dismiss(); + mProgressDialog.dismiss(); } @Override @@ -47,11 +98,6 @@ protected void initPresenter() { mPresenter = new SettingsPresenter(this); } - @Override - protected void initView() { - mAlertDialog = new AlertDialog.Builder(getActivity(), R.style.AppTheme_Dialog_Alert).setCancelable(false).create(); - } - @Override protected BasePresenter getPresenter() { return mPresenter; @@ -62,13 +108,13 @@ protected int getLayoutView() { return R.layout.fragment_settings; } - public void showAlertDialog(String msg) { - mAlertDialog.setMessage(msg); - mAlertDialog.show(); + public void showProgressDialog(String msg) { + mProgressDialog.setMessage(msg); + mProgressDialog.show(); } - public void hideAlertDialog() { - mAlertDialog.hide(); + public void hideProgressDialog() { + mProgressDialog.hide(); } public void showSnackbar(String msg) { @@ -77,4 +123,6 @@ public void showSnackbar(String msg) { } } + + } diff --git a/app/src/main/java/com/hiroshi/cimoc/utils/DialogFactory.java b/app/src/main/java/com/hiroshi/cimoc/utils/DialogFactory.java new file mode 100644 index 00000000..27158db7 --- /dev/null +++ b/app/src/main/java/com/hiroshi/cimoc/utils/DialogFactory.java @@ -0,0 +1,39 @@ +package com.hiroshi.cimoc.utils; + +import android.content.Context; +import android.content.DialogInterface.OnClickListener; +import android.support.v7.app.AlertDialog; + +import com.hiroshi.cimoc.R; + +/** + * Created by Hiroshi on 2016/8/4. + */ +public class DialogFactory { + + public static AlertDialog buildPositiveDialog(Context context, String title, String message, OnClickListener listener) { + AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.AppTheme_Dialog_Alert); + builder.setTitle(title); + builder.setMessage(message); + builder.setPositiveButton("确定", listener); + builder.setNegativeButton("取消", null); + return builder.create(); + } + + public static AlertDialog buildSingleChoiceDialog(Context context, String title, int array, int choice, + OnClickListener listener, OnClickListener positive) { + return buildSingleChoiceDialog(context, title, context.getResources().getStringArray(array), choice, listener, positive); + } + + public static AlertDialog buildSingleChoiceDialog(Context context, String title, String[] array, int choice, + OnClickListener listener, OnClickListener positive) { + AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.AppTheme_Dialog_Alert); + builder.setTitle(title); + builder.setSingleChoiceItems(array, choice, listener); + if (positive != null) { + builder.setPositiveButton("确定", positive); + } + return builder.create(); + } + +} diff --git a/app/src/main/java/com/hiroshi/cimoc/utils/PreferenceMaster.java b/app/src/main/java/com/hiroshi/cimoc/utils/PreferenceMaster.java new file mode 100644 index 00000000..b728b44c --- /dev/null +++ b/app/src/main/java/com/hiroshi/cimoc/utils/PreferenceMaster.java @@ -0,0 +1,69 @@ +package com.hiroshi.cimoc.utils; + +import android.content.Context; +import android.content.SharedPreferences; + +import com.hiroshi.cimoc.R; + +/** + * Created by Hiroshi on 2016/8/4. + */ +public class PreferenceMaster { + + public static final String PREF_EX = "pref_ex"; + public static final String PREF_HOME = "pref_home"; + public static final String PREF_READER = "pref_reader"; + + private static final String PREFERENCES_NAME = "cimoc_preferences"; + + private SharedPreferences mSharedPreferences; + + public PreferenceMaster(Context context) { + mSharedPreferences = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE); + } + + public String getString(String key, String defValue) { + return mSharedPreferences.getString(key, defValue); + } + + public boolean getBoolean(String key, boolean defValue) { + return mSharedPreferences.getBoolean(key, defValue); + } + + public int getInt(String key, int defValue) { + return mSharedPreferences.getInt(key, defValue); + } + + public long getLong(String key, long defValue) { + return mSharedPreferences.getLong(key, defValue); + } + + public void putString(String key, String value) { + mSharedPreferences.edit().putString(key, value).apply(); + } + + public void putBoolean(String key, boolean value) { + mSharedPreferences.edit().putBoolean(key, value).apply(); + } + + public void putInt(String key, int value) { + mSharedPreferences.edit().putInt(key, value).apply(); + } + + public void putLong(String key, long value) { + mSharedPreferences.edit().putLong(key, value).apply(); + } + + public static String getTitleById(int id) { + switch (id) { + default: + case R.id.drawer_cimoc: + return "Cimoc"; + case R.id.drawer_favorite: + return "我的漫画"; + case R.id.drawer_history: + return "历史阅读"; + } + } + +} diff --git a/app/src/main/res/drawable-hdpi/ic_sync_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_sync_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..f0072e1163d95c102c9bf9782f43cefc22d07be6 GIT binary patch literal 387 zcmV-}0et?6P)NklL0^LQS)By{Krz;i97yD?Xegd8Kuz3ltLp@03{47&mP>Ww}Coo4enJ1Cz{l& z#rAi!=ftH3z;)@rcBThhM9?P(vvYK)122x}p&y!*ntUJW!QC8G8L*sW>8_oFL6wKT zfuG^{wcsWX{Q`>+x&mz;`U~n1It5R8XbpBlXdk@gp%vH*pT z0?<3(fKn=ck9-Btx^iltn0i0H@M2mam5Cj@Gf1n8p|mSET2I~zPBiU=DS$?%6dIXw hXk^Nvkr6}X{SWy|q5;?r4%7eu002ovPDHLkV1jzusXqV! literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_sync_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_sync_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..7a7a771e2708b4d4d27f6fccbba310b8cdbae367 GIT binary patch literal 494 zcmV6y%7{>9}C~YJujzTRs+~V3r1RbUHBZT0mc|j;mb(TUZF70P2WDw%$(qs$)7aO!! z{($fI~^Zp(Nl?5^(NTvt+`UAv>D^ zoVHe+vtJHSHK%mrK!kuP)g}*li(L*m<{H*5IN1De+F`)#4pEi3Xgw}aFr}Lhyb3%O z?@=(y1)lK>4?K34sG2Gd_yo{OSYv(WsBsSPh##ouSmuVP8~SPB4eBfRvVjgW)F2If zM7_lVJ3*bLfzPPdA>asgl?J|{9*2NE)FKW1LER4l+o;<#P@}d&zys9pG_XYNhJYui zWg3{E4v8N!Owzy@bsPdl`M>E9bxkL5(dPLVZHEWig!(*m3V>W0uT9uf=l`hppD1|jEV&c<_zhu24aNKwgVB0 z87CaE$2P1xA9LD-8vjA2{={~aI7TY kSV_RKl7M4n0sF^*zbqi?c+z)hNB{r;07*qoM6N<$f`H-Bp#T5? literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_sync_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_sync_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..be061bfe0339b41d0fc337dc4879168878dce520 GIT binary patch literal 734 zcmV<40wMj0P)xt#PM<)jC> zob({&qz5S{IY>F_LCQ%1^5?)ES5(+%lUaI=AUns&F-vsWL3WO&!3O<_K~CzdP)PjB zoSZTgA7mrdnEw0!_D?7>!W>(iR=P)8wt!wxZAeQq^xZn z>KR8@KG1s^QlW#)P$m5?v6v5ZEF(UX8EaRj9pwS_qZu=UCS_WSo^a5-4ERB2uK&1@ zi8JA#kJ7$L7NNFf;(9pfo3y`)0@B}nFC6q!+FwQijmpHca8OO!pGN_8%fxCps3q-> zqJW;t#M^Mtoo<6sKpnapg@dl7y%+`5DHDH%gDTQK5(V^1zii>4eQBSI0-BSFU&BG0 z(!Lc1^hsBcaL}x@pGN^1kB(k66K2k9_i(kWA3J8y7n$}w-#)a2em90qoX6;Wwww>t zMMH)h7?;=qF8_Rko*9;W@2fE0q!0OT9sSe=bklZk#FO+tMaxBT1x=Mw8;~FAt?lMo z;Pf78ybZ{QWWL)EQA2aXLR*lL4NN}3|~?cHy3O( z&nVrx4cbWlk4|xoZw#c6hX*;alk6a^0?X9xBs)l}k2M;pLGH1;$Pul?ugs|)W>{yB zGpgK1{-d^+2PY{=Iq5;lNe@y^dXRF`gOrmV - \ No newline at end of file + android:layout_height="match_parent"> + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml index bd1f6f10..67a72a10 100644 --- a/app/src/main/res/layout/fragment_settings.xml +++ b/app/src/main/res/layout/fragment_settings.xml @@ -80,6 +80,28 @@ android:textColor="?attr/colorAccent" android:textSize="14sp" android:text="@string/settings_other"/> + + + + + CC图库 - CCTuku E站 - EHentai + + Cimoc + 我的漫画 + 历史阅读 + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4fef436f..ed5d3ab8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -20,7 +20,9 @@ 前面没有了 :( - version: 1.0.0 + NEW + + version: 1.1.0 备份设置 备份 @@ -28,6 +30,7 @@ 恢复 从本地文件中恢复 其他设置 + 首页设置 清除历史纪录 清除缓存 From 17d75482da43dd73b633aa32c78d6ac31ca4169b Mon Sep 17 00:00:00 2001 From: hiroshi Date: Sat, 6 Aug 2016 00:32:48 +0800 Subject: [PATCH 003/521] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E6=A8=AA=E5=B1=8F?= =?UTF-8?q?=E5=8D=B7=E7=BA=B8=E9=98=85=E8=AF=BB=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E6=B8=85=E9=99=A4=E5=8E=86=E5=8F=B2=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/misc.xml | 2 +- app/src/main/AndroidManifest.xml | 5 + .../com/hiroshi/cimoc/core/ComicManager.java | 10 +- .../java/com/hiroshi/cimoc/model/Chapter.java | 10 ++ .../com/hiroshi/cimoc/model/MiniComic.java | 4 +- .../cimoc/presenter/DetailPresenter.java | 3 +- .../cimoc/presenter/HistoryPresenter.java | 7 + .../cimoc/presenter/ReaderPresenter.java | 56 ++++---- .../cimoc/presenter/ResultPresenter.java | 15 +-- .../cimoc/presenter/SettingsPresenter.java | 10 -- .../presenter/StreamReaderPresenter.java | 122 ++++++++++++++++++ .../cimoc/ui/activity/DetailActivity.java | 2 +- .../cimoc/ui/activity/ReaderActivity.java | 38 ++++-- .../cimoc/ui/activity/ResultActivity.java | 28 ++-- .../ui/activity/StreamReaderActivity.java | 121 +++++++++++++++++ .../hiroshi/cimoc/ui/adapter/BaseAdapter.java | 21 ++- .../cimoc/ui/adapter/ChapterAdapter.java | 18 ++- .../cimoc/ui/adapter/ComicAdapter.java | 18 +-- .../cimoc/ui/adapter/FavoriteAdapter.java | 69 ++++++++++ .../cimoc/ui/adapter/PicturePagerAdapter.java | 48 ++++--- .../ui/adapter/PictureStreamAdapter.java | 75 +++++++++++ .../cimoc/ui/adapter/PreloadAdapter.java | 85 +++++------- .../ui/custom/photo/PhotoDraweeView.java | 8 ++ .../photo/PhotoDraweeViewController.java | 103 +++++++++++++-- .../cimoc/ui/fragment/AboutFragment.java | 7 +- .../cimoc/ui/fragment/BaseFragment.java | 7 + .../cimoc/ui/fragment/CimocFragment.java | 13 +- .../cimoc/ui/fragment/FavoriteFragment.java | 86 ++++++------ .../cimoc/ui/fragment/HistoryFragment.java | 35 +++-- .../cimoc/ui/fragment/SettingsFragment.java | 25 +--- .../hiroshi/cimoc/utils/DialogFactory.java | 26 ++-- .../drawable-hdpi/ic_delete_white_24dp.png | Bin 0 -> 161 bytes .../drawable-xhdpi/ic_delete_white_24dp.png | Bin 0 -> 151 bytes .../drawable-xxhdpi/ic_delete_white_24dp.png | Bin 0 -> 194 bytes app/src/main/res/layout/activity_reader.xml | 2 +- .../res/layout/activity_stream_reader.xml | 65 ++++++++++ app/src/main/res/layout/fragment_history.xml | 26 +++- app/src/main/res/layout/fragment_settings.xml | 11 +- app/src/main/res/layout/item_picture.xml | 1 - app/src/main/res/values/colors.xml | 2 +- app/src/main/res/values/strings.xml | 18 ++- 41 files changed, 908 insertions(+), 294 deletions(-) create mode 100644 app/src/main/java/com/hiroshi/cimoc/presenter/StreamReaderPresenter.java create mode 100644 app/src/main/java/com/hiroshi/cimoc/ui/activity/StreamReaderActivity.java create mode 100644 app/src/main/java/com/hiroshi/cimoc/ui/adapter/FavoriteAdapter.java create mode 100644 app/src/main/java/com/hiroshi/cimoc/ui/adapter/PictureStreamAdapter.java create mode 100644 app/src/main/res/drawable-hdpi/ic_delete_white_24dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_delete_white_24dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_delete_white_24dp.png create mode 100644 app/src/main/res/layout/activity_stream_reader.xml diff --git a/.idea/misc.xml b/.idea/misc.xml index fbb68289..5d199810 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -37,7 +37,7 @@ - + diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b64a9487..e618bded 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -34,6 +34,11 @@ android:theme="@style/ReaderTheme" android:screenOrientation="portrait"/> + + diff --git a/app/src/main/java/com/hiroshi/cimoc/core/ComicManager.java b/app/src/main/java/com/hiroshi/cimoc/core/ComicManager.java index 2b982229..8e52e0ef 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/ComicManager.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/ComicManager.java @@ -128,8 +128,10 @@ public MiniComic[] arrayFavorite() { long id = cursor.getLong(0); int source = cursor.getInt(1); String cid = cursor.getString(2); + String title = cursor.getString(3); + String cover = cursor.getString(4); String update = cursor.getString(5); - array[count++] = new MiniComic(id, source, cid, null, null, update); + array[count++] = new MiniComic(id, source, cid, title, cover, update, false); } cursor.close(); return array; @@ -162,7 +164,8 @@ private List listByCursor(Cursor cursor) { String title = cursor.getString(3); String cover = cursor.getString(4); String update = cursor.getString(5); - list.add(new MiniComic(id, source, cid, title, cover, update)); + boolean status = cursor.getLong(6) == NEW_VALUE; + list.add(new MiniComic(id, source, cid, title, cover, update, status)); } cursor.close(); return list; @@ -180,6 +183,9 @@ public void setComic(Long id, int source, String cid) { .unique(); } else { comic = mComicDao.load(id); + if (comic.getFavorite() != null && comic.getFavorite() == NEW_VALUE) { + comic.setFavorite(System.currentTimeMillis()); + } } if (comic == null) { comic = new Comic(source, cid); diff --git a/app/src/main/java/com/hiroshi/cimoc/model/Chapter.java b/app/src/main/java/com/hiroshi/cimoc/model/Chapter.java index c4f5b466..0ff9fb6e 100644 --- a/app/src/main/java/com/hiroshi/cimoc/model/Chapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/model/Chapter.java @@ -7,10 +7,12 @@ public class Chapter { String title; String path; + int count; public Chapter(String title, String path) { this.title = title; this.path = path; + this.count = 0; } public String getTitle() { @@ -21,4 +23,12 @@ public String getPath() { return path; } + public int getCount() { + return count; + } + + public void setCount(int count) { + this.count = count; + } + } diff --git a/app/src/main/java/com/hiroshi/cimoc/model/MiniComic.java b/app/src/main/java/com/hiroshi/cimoc/model/MiniComic.java index 492c1aab..217c0edd 100644 --- a/app/src/main/java/com/hiroshi/cimoc/model/MiniComic.java +++ b/app/src/main/java/com/hiroshi/cimoc/model/MiniComic.java @@ -13,14 +13,14 @@ public class MiniComic { private String update; private boolean status; - public MiniComic(Long id, int source, String cid, String title, String cover, String update) { + public MiniComic(Long id, int source, String cid, String title, String cover, String update, boolean status) { this.id = id; this.source = source; this.cid = cid; this.title = title; this.cover = cover; this.update = update; - this.status = false; + this.status = status; } public MiniComic(Comic comic) { diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/DetailPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/DetailPresenter.java index 09754fdc..63867cc5 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/DetailPresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/DetailPresenter.java @@ -10,6 +10,7 @@ import com.hiroshi.cimoc.ui.activity.DetailActivity; import com.hiroshi.cimoc.ui.activity.ReaderActivity; import com.hiroshi.cimoc.model.EventMessage; +import com.hiroshi.cimoc.ui.activity.StreamReaderActivity; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; @@ -50,7 +51,7 @@ public void saveComic() { public void onItemClick(int position) { if (position != 0) { - Intent intent = ReaderActivity.createIntent(mDetailActivity, position - 1); + Intent intent = StreamReaderActivity.createIntent(mDetailActivity, position - 1); mDetailActivity.startActivity(intent); } } diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/HistoryPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/HistoryPresenter.java index 5e45c6f5..3b381aa0 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/HistoryPresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/HistoryPresenter.java @@ -39,6 +39,10 @@ public void onPositiveClick(MiniComic comic) { mComicManager.removeHistory(comic.getId()); } + public void onHistoryClearClick() { + mComicManager.cleanHistory(); + } + @Subscribe(threadMode = ThreadMode.MAIN) public void onEvent(EventMessage msg) { switch (msg.getType()) { @@ -46,7 +50,10 @@ public void onEvent(EventMessage msg) { mHistoryFragment.updateItem((MiniComic) msg.getData()); break; case EventMessage.DELETE_HISTORY: + int count = (int) msg.getData(); mHistoryFragment.clearItem(); + mHistoryFragment.hideProgressDialog(); + mHistoryFragment.showSnackbar("删除成功 共 " + count + " 条记录"); break; } } diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/ReaderPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/ReaderPresenter.java index 6d3dbe6d..faf1d949 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/ReaderPresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/ReaderPresenter.java @@ -12,10 +12,6 @@ import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - /** * Created by Hiroshi on 2016/7/8. */ @@ -36,9 +32,7 @@ public class ReaderPresenter extends BasePresenter { public ReaderPresenter(ReaderActivity activity, int position) { mReaderActivity = activity; mComicManager = ComicManager.getInstance(); - List list = new ArrayList<>(mComicManager.getChapters()); - Collections.reverse(list); - mPreloadAdapter = new PreloadAdapter(list.toArray(new Chapter[list.size()]), list.size() - position - 1, PicturePagerAdapter.MAX_COUNT / 2 + 1); + mPreloadAdapter = new PreloadAdapter(mComicManager.getChapters(), position); mManga = Kami.getMangaById(mComicManager.getSource()); } @@ -74,21 +68,27 @@ public void onPageStateIdle(boolean isFirst) { } } - public void onPageSelected(int position) { - boolean flag = mPreloadAdapter.moveToPosition(position); - Chapter chapter = mPreloadAdapter.getValidChapter(); + public void onChapterToNext() { + Chapter chapter = mPreloadAdapter.nextChapter(); + if (chapter == null) { + mReaderActivity.hideChapterInfo(); + } else { + switchChapter(1, chapter.getCount(), chapter.getTitle(), chapter.getPath()); + } + } + + public void onChapterToPrev() { + Chapter chapter = mPreloadAdapter.prevChapter(); if (chapter == null) { mReaderActivity.hideChapterInfo(); - } else if (flag) { - switchChapter(mPreloadAdapter.getValidProgress()); } else { - mReaderActivity.setReadProgress(mPreloadAdapter.getValidProgress()); + switchChapter(chapter.getCount(), chapter.getCount(), chapter.getTitle(), chapter.getPath()); } } public void onProgressChanged(int value, boolean fromUser) { if (fromUser) { - mReaderActivity.setCurrentItem(mPreloadAdapter.getCurrentOffset() + value - 1); + mReaderActivity.setCurrentItem(mPreloadAdapter.getOffset() + value); } } @@ -96,30 +96,36 @@ public int getSource() { return mComicManager.getSource(); } - private void switchChapter(int page) { - mReaderActivity.updateChapterInfo(page, mPreloadAdapter.getMax(), mPreloadAdapter.getValidChapter().getTitle()); - mComicManager.setLast(mPreloadAdapter.getValidChapter().getPath()); + private void switchChapter(int progress, int max, String title, String path) { + mReaderActivity.updateChapterInfo(max, title); + if (progress != -1) { + mReaderActivity.setReadProgress(progress); + } + mComicManager.setLast(path); } @Subscribe(threadMode = ThreadMode.MAIN) public void onEvent(EventMessage msg) { - String[] array; switch (msg.getType()) { case EventMessage.PARSE_PIC_SUCCESS: - array = (String[]) msg.getData(); + String[] array = (String[]) msg.getData(); + Chapter chapter; if (status == LOAD_PREV) { mReaderActivity.setPrevImage(array); - mPreloadAdapter.movePrev(array.length); + chapter = mPreloadAdapter.movePrev(); } else { mReaderActivity.setNextImage(array); - mPreloadAdapter.moveNext(array.length); + chapter = mPreloadAdapter.moveNext(); } + chapter.setCount(array.length); int page = mComicManager.getPage(); - if (!load && mComicManager.getLast().equals(mPreloadAdapter.getValidChapter().getPath()) && page != -1) { - switchChapter(page); - mReaderActivity.setCurrentItem(mPreloadAdapter.getCurrentOffset() + page - 1); + if (!load && chapter.getPath().equals(mComicManager.getLast()) && page != -1) { + switchChapter(-1, array.length, chapter.getTitle(), chapter.getPath()); + mReaderActivity.setCurrentItem(page); + } else if (status == LOAD_PREV) { + switchChapter(array.length, array.length, chapter.getTitle(), chapter.getPath()); } else { - switchChapter(mPreloadAdapter.getValidProgress()); + switchChapter(1, array.length, chapter.getTitle(), chapter.getPath()); } load = true; mReaderActivity.setNoneLimit(); diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/ResultPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/ResultPresenter.java index 5d0755f5..aafaac57 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/ResultPresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/ResultPresenter.java @@ -46,19 +46,14 @@ public void onDestroy() { mManga.cancel(); } - public void onScrolled(int dy) { - int lastItem = mResultActivity.findLastItemPosition(); - int itemCount = mResultActivity.getItemCount(); - if (lastItem >= itemCount - 4 && dy > 0) { - if (!isLoading) { - isLoading = true; - mManga.search(keyword, ++page); - } + public void onScrolled(int dy, int last, int count) { + if (last >= count - 4 && dy > 0 && !isLoading) { + isLoading = true; + mManga.search(keyword, ++page); } } - public void onItemClick(int position) { - Comic comic = mResultActivity.getItem(position); + public void onItemClick(Comic comic) { Intent intent = DetailActivity.createIntent(mResultActivity, comic.getId(), comic.getSource(), comic.getCid()); mResultActivity.startActivity(intent); } diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/SettingsPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/SettingsPresenter.java index 54b3ba5b..a984dd69 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/SettingsPresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/SettingsPresenter.java @@ -57,19 +57,9 @@ public void onRestorePositiveBtnClick(String name) { mComicManager.restoreFavorite(list); } - public void onHistoryBtnClick() { - mSettingsFragment.showProgressDialog("正在删除.."); - mComicManager.cleanHistory(); - } - @Subscribe(threadMode = ThreadMode.MAIN) public void onEvent(EventMessage msg) { switch (msg.getType()) { - case EventMessage.DELETE_HISTORY: - int count = (int) msg.getData(); - mSettingsFragment.hideProgressDialog(); - mSettingsFragment.showSnackbar("删除成功 共 " + count + " 条记录"); - break; case EventMessage.RESTORE_FAVORITE: List list = (List) msg.getData(); mSettingsFragment.hideProgressDialog(); diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/StreamReaderPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/StreamReaderPresenter.java new file mode 100644 index 00000000..775c1f49 --- /dev/null +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/StreamReaderPresenter.java @@ -0,0 +1,122 @@ +package com.hiroshi.cimoc.presenter; + +import com.hiroshi.cimoc.core.ComicManager; +import com.hiroshi.cimoc.core.Kami; +import com.hiroshi.cimoc.core.base.Manga; +import com.hiroshi.cimoc.model.Chapter; +import com.hiroshi.cimoc.model.EventMessage; +import com.hiroshi.cimoc.ui.activity.StreamReaderActivity; +import com.hiroshi.cimoc.ui.adapter.PreloadAdapter; + +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +/** + * Created by Hiroshi on 2016/8/5. + */ +public class StreamReaderPresenter extends BasePresenter { + + private final static int LOAD_NULL = 0; + private final static int LOAD_PREV = 1; + private final static int LOAD_NEXT = 2; + + private StreamReaderActivity mStreamReaderActivity; + private PreloadAdapter mPreloadAdapter; + private ComicManager mComicManager; + private Manga mManga; + + private int status; + + public StreamReaderPresenter(StreamReaderActivity activity, int position) { + mStreamReaderActivity = activity; + mComicManager = ComicManager.getInstance(); + mPreloadAdapter = new PreloadAdapter(mComicManager.getChapters(), position); + mManga = Kami.getMangaById(mComicManager.getSource()); + } + + @Override + public void onCreate() { + super.onCreate(); + status = LOAD_NEXT; + mManga.browse(mComicManager.getCid(), mPreloadAdapter.getNextChapter().getPath()); + } + + @Override + public void onDestroy() { + super.onDestroy(); + mManga.cancel(); + } + + public void onScrolled(int dy, int last, int count) { + if (last >= count - 1 && dy > 0 && status == LOAD_NULL) { + Chapter chapter = mPreloadAdapter.getNextChapter(); + if (chapter != null) { + status = LOAD_NEXT; + mManga.browse(mComicManager.getCid(), chapter.getPath()); + } + } else if (last <= 1 && dy < 0 && status == LOAD_NULL) { + Chapter chapter = mPreloadAdapter.getPrevChapter(); + if (chapter != null) { + status = LOAD_PREV; + mManga.browse(mComicManager.getCid(), chapter.getPath()); + } + } + } + + public void afterRead(int progress) { + mComicManager.afterRead(progress); + } + + public void onChapterToNext() { + Chapter chapter = mPreloadAdapter.nextChapter(); + if (chapter != null) { + switchChapter(1, chapter.getCount(), chapter.getTitle(), chapter.getPath()); + } + } + + public void onChapterToPrev() { + Chapter chapter = mPreloadAdapter.prevChapter(); + if (chapter != null) { + switchChapter(chapter.getCount(), chapter.getCount(), chapter.getTitle(), chapter.getPath()); + } + } + + public void onProgressChanged(int value, boolean fromUser) { + } + + public int getSource() { + return mComicManager.getSource(); + } + + private void switchChapter(int progress, int max, String title, String path) { + mStreamReaderActivity.updateChapterInfo(max, title); + if (progress != -1) { + mStreamReaderActivity.setReadProgress(progress); + } + mComicManager.setLast(path); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onEvent(EventMessage msg) { + switch (msg.getType()) { + case EventMessage.PARSE_PIC_SUCCESS: + String[] array = (String[]) msg.getData(); + Chapter chapter; + if (status == LOAD_PREV) { + mStreamReaderActivity.setPrevImage(array); + chapter = mPreloadAdapter.movePrev(); + } else { + mStreamReaderActivity.setNextImage(array); + chapter = mPreloadAdapter.moveNext(); + } + chapter.setCount(array.length); + switchChapter(1, array.length, chapter.getTitle(), chapter.getPath()); + status = LOAD_NULL; + break; + case EventMessage.PARSE_PIC_FAIL: + case EventMessage.NETWORK_ERROR: + break; + } + } + +} diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/DetailActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/DetailActivity.java index 33343230..1f653304 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/DetailActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/DetailActivity.java @@ -49,7 +49,7 @@ protected void initToolbar() { mToolbar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - finish(); + onBackPressed(); } }); } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java index 8d75b437..bcf3d7f7 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java @@ -38,6 +38,8 @@ public class ReaderActivity extends BaseActivity { private PicturePagerAdapter mPagerAdapter; private ReaderPresenter mPresenter; + private int progress; + @Override public void onBackPressed() { mPresenter.afterRead(mSeekBar.getProgress()); @@ -46,6 +48,8 @@ public void onBackPressed() { @Override protected void initView() { + progress = 0; + mPagerAdapter = new PicturePagerAdapter(new LinkedList(), getLayoutInflater(), new PhotoDraweeViewController.OnSingleTapListener() { @Override @@ -60,14 +64,26 @@ public void onSingleTap(View view, float x, float y) { } } }, ControllerBuilderFactory.getControllerBuilder(mPresenter.getSource(), this)); + mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {} @Override public void onPageSelected(int position) { - mViewPager.setLimit(mPagerAdapter.getLimitByPosition(position)); - mPresenter.onPageSelected(position); + int current = mPagerAdapter.getCurrent(); + if (position == current) { + return; + } + mPagerAdapter.setCurrent(position); + mViewPager.setLimit(mPagerAdapter.getLimit()); + if (position > current && progress == mSeekBar.getMax()) { + mPresenter.onChapterToNext(); + } else if (position < current && progress == 1) { + mPresenter.onChapterToPrev(); + } else { + setReadProgress(progress + position - current); + } } @Override @@ -81,7 +97,7 @@ public void onPageScrollStateChanged(int state) { }); mViewPager.setAdapter(mPagerAdapter); mViewPager.setCurrentItem(PicturePagerAdapter.MAX_COUNT / 2 + 1, false); - mViewPager.setOffscreenPageLimit(4); + mViewPager.setOffscreenPageLimit(3); mSeekBar.setOnProgressChangeListener(new DiscreteSeekBar.OnProgressChangeListener() { @Override @@ -143,22 +159,20 @@ public void hideChapterInfo() { mChapterTitle.setText(null); } - public void setCurrentItem(int item) { - mViewPager.setCurrentItem(item, false); + public void setCurrentItem(int offset) { + mViewPager.setCurrentItem(mPagerAdapter.getLeft() + offset, false); } - public void updateChapterInfo(int progress, int max, String title) { + public void updateChapterInfo(int max, String title) { mSeekBar.setMax(max); - mSeekBar.setProgress(progress); - String str = progress + "/" + max; - mChapterPage.setText(str); mChapterTitle.setText(title); } - public void setReadProgress(int progress) { - mSeekBar.setProgress(progress); - String pageString = progress + "/" + mSeekBar.getMax(); + public void setReadProgress(int value) { + mSeekBar.setProgress(value); + String pageString = value + "/" + mSeekBar.getMax(); mChapterPage.setText(pageString); + progress = value; } public static Intent createIntent(Context context, int position) { diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/ResultActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/ResultActivity.java index 60d8a891..dcd7665a 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/ResultActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/ResultActivity.java @@ -29,7 +29,7 @@ public class ResultActivity extends BaseActivity { public static final String EXTRA_KEYWORD = "extra_keyword"; public static final String EXTRA_SOURCE = "extra_source"; - @BindView(R.id.result_comic_list) RecyclerView mResultList; + @BindView(R.id.result_comic_list) RecyclerView mRecyclerView; @BindView(R.id.result_progress_bar) ProgressBar mProgressBar; @BindView(R.id.result_layout) LinearLayout mLinearLayout; @@ -50,7 +50,7 @@ protected void initToolbar() { mToolbar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - finish(); + onBackPressed(); } }); } @@ -59,19 +59,19 @@ public void onClick(View v) { protected void initView() { mLayoutManager = new LinearLayoutManager(this); mResultAdapter = new ResultAdapter(this, new LinkedList()); - mResultList.setLayoutManager(mLayoutManager); - mResultList.setAdapter(mResultAdapter); - mResultList.addItemDecoration(mResultAdapter.getItemDecoration()); - mResultList.addOnScrollListener(new RecyclerView.OnScrollListener() { + mRecyclerView.setLayoutManager(mLayoutManager); + mRecyclerView.setAdapter(mResultAdapter); + mRecyclerView.addItemDecoration(mResultAdapter.getItemDecoration()); + mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { - mPresenter.onScrolled(dy); + mPresenter.onScrolled(dy, mLayoutManager.findLastVisibleItemPosition(), mResultAdapter.getItemCount()); } }); mResultAdapter.setOnItemClickListener(new BaseAdapter.OnItemClickListener() { @Override public void onItemClick(View view, int position) { - mPresenter.onItemClick(position); + mPresenter.onItemClick(mResultAdapter.getItem(position)); } }); } @@ -94,7 +94,7 @@ protected BasePresenter getPresenter() { public void hideProgressBar() { if (mProgressBar.isShown()) { mProgressBar.setVisibility(View.GONE); - mResultList.setVisibility(View.VISIBLE); + mRecyclerView.setVisibility(View.VISIBLE); } } @@ -108,16 +108,6 @@ public void addAll(List list) { mResultAdapter.addAll(list); } - public int findLastItemPosition() { - return mLayoutManager.findLastVisibleItemPosition(); - } - - public int getItemCount() { - return mLayoutManager.getItemCount(); - } - - public Comic getItem(int position) { return mResultAdapter.getItem(position); } - public static Intent createIntent(Context context, String keyword, int source) { Intent intent = new Intent(context, ResultActivity.class); intent.putExtra(EXTRA_KEYWORD, keyword); diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/StreamReaderActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/StreamReaderActivity.java new file mode 100644 index 00000000..5e4bd5d6 --- /dev/null +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/StreamReaderActivity.java @@ -0,0 +1,121 @@ +package com.hiroshi.cimoc.ui.activity; + +import android.content.Context; +import android.content.Intent; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.hiroshi.cimoc.R; +import com.hiroshi.cimoc.presenter.BasePresenter; +import com.hiroshi.cimoc.presenter.StreamReaderPresenter; +import com.hiroshi.cimoc.ui.adapter.PictureStreamAdapter; +import com.hiroshi.cimoc.utils.ControllerBuilderFactory; + +import org.adw.library.widgets.discreteseekbar.DiscreteSeekBar; + +import java.util.Arrays; + +import butterknife.BindView; + +/** + * Created by Hiroshi on 2016/8/5. + */ +public class StreamReaderActivity extends BaseActivity { + + public static final String EXTRA_POSITION = "extra_position"; + + @BindView(R.id.reader_recycler_view) RecyclerView mRecyclerView; + @BindView(R.id.reader_chapter_title) TextView mChapterTitle; + @BindView(R.id.reader_chapter_page) TextView mChapterPage; + @BindView(R.id.reader_tool_bar) LinearLayout mToolLayout; + @BindView(R.id.reader_seek_bar) DiscreteSeekBar mSeekBar; + + private PictureStreamAdapter mStreamAdapter; + private StreamReaderPresenter mPresenter; + private LinearLayoutManager mLayoutManager; + + private int progress; + + @Override + public void onBackPressed() { + mPresenter.afterRead(mSeekBar.getProgress()); + super.onBackPressed(); + } + + @Override + protected void initView() { + progress = 0; + mLayoutManager = new LinearLayoutManager(this); + mStreamAdapter = new PictureStreamAdapter(this, ControllerBuilderFactory.getControllerBuilder(mPresenter.getSource(), this)); + mRecyclerView.setItemAnimator(null); + mRecyclerView.setLayoutManager(mLayoutManager); + mRecyclerView.setAdapter(mStreamAdapter); + mRecyclerView.addItemDecoration(mStreamAdapter.getItemDecoration()); + mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + mPresenter.onScrolled(dy, mLayoutManager.findLastVisibleItemPosition(), mStreamAdapter.getItemCount()); + } + }); + } + + @Override + protected void initToolbar() {} + + @Override + protected void initPresenter() { + int position = getIntent().getIntExtra(EXTRA_POSITION, 0); + mPresenter = new StreamReaderPresenter(this, position); + } + + @Override + protected String getDefaultTitle() { + return null; + } + + @Override + protected BasePresenter getPresenter() { + return mPresenter; + } + + @Override + protected int getLayoutView() { + return R.layout.activity_stream_reader; + } + + public void hideChapterInfo() { + mToolLayout.setVisibility(View.GONE); + mChapterPage.setText(null); + mChapterTitle.setText(null); + } + + public void setPrevImage(String[] array) { + mStreamAdapter.addAll(0, Arrays.asList(array)); + } + + public void setNextImage(String[] array) { + mStreamAdapter.addAll(Arrays.asList(array)); + } + + public void updateChapterInfo(int max, String title) { + mSeekBar.setMax(max); + mChapterTitle.setText(title); + } + + public void setReadProgress(int value) { + mSeekBar.setProgress(value); + String pageString = value + "/" + mSeekBar.getMax(); + mChapterPage.setText(pageString); + progress = value; + } + + public static Intent createIntent(Context context, int position) { + Intent intent = new Intent(context, StreamReaderActivity.class); + intent.putExtra(EXTRA_POSITION, position); + return intent; + } + +} diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/BaseAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/BaseAdapter.java index 9b788998..b70c8f1c 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/BaseAdapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/BaseAdapter.java @@ -26,33 +26,34 @@ public BaseAdapter(Context context, List list) { mInflater = LayoutInflater.from(context); } + public void add(T data) { + add(mDataSet.size(), data); + } + public void add(int location, T data) { mDataSet.add(location, data); notifyItemInserted(location); } - public void add(T data) { - add(mDataSet.size(), data); - } - public void addAll(List data) { addAll(mDataSet.size(), data); } public void addAll(int location, List data) { mDataSet.addAll(location, data); - notifyDataSetChanged(); + notifyItemRangeInserted(location, location + data.size()); } public void remove(T data) { - if (mDataSet.remove(data)) { - notifyDataSetChanged(); + int position = mDataSet.indexOf(data); + if (position != -1) { + remove(position); } } public void remove(int position) { mDataSet.remove(position); - notifyDataSetChanged(); + notifyItemRemoved(position); } public void clear() { @@ -70,10 +71,6 @@ public T getItem(int position) { return mDataSet.get(position); } - public List getDataSet() { - return mDataSet; - } - @Override public int getItemCount() { return mDataSet.size(); diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ChapterAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ChapterAdapter.java index e26674cf..f340237c 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ChapterAdapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ChapterAdapter.java @@ -135,9 +135,21 @@ public int getSpanSize(int position) { }); } - public void setLast(String last) { - this.last = last; - notifyDataSetChanged(); + public void setLast(String value) { + if (last == null || value.equals(last)) { + last = value; + return; + } + String temp = last; + last = value; + for (int i = 0; i != mDataSet.size(); ++i) { + String path = mDataSet.get(i).getPath(); + if (path.equals(last)) { + notifyItemChanged(i + 1); + } else if (path.equals(temp)) { + notifyItemChanged(i + 1); + } + } } } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ComicAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ComicAdapter.java index 88b54390..45344f26 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ComicAdapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ComicAdapter.java @@ -14,6 +14,7 @@ import com.hiroshi.cimoc.model.MiniComic; import com.hiroshi.cimoc.utils.ControllerBuilderFactory; +import java.util.LinkedList; import java.util.List; import butterknife.BindView; @@ -52,11 +53,6 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { viewHolder.comicSource.setText(Kami.getSourceById(comic.getSource())); PipelineDraweeControllerBuilder builder = ControllerBuilderFactory.getControllerBuilder(comic.getSource(), mContext); viewHolder.comicImage.setController(builder.setUri(comic.getCover()).build()); - if (comic.getStatus()) { - viewHolder.comicNew.setVisibility(View.VISIBLE); - } else { - viewHolder.comicNew.setVisibility(View.INVISIBLE); - } } @Override @@ -70,9 +66,15 @@ public void getItemOffsets(Rect outRect, View view, RecyclerView parent, Recycle } public void update(MiniComic comic) { - mDataSet.remove(comic); - mDataSet.add(0, comic); - notifyDataSetChanged(); + int position = mDataSet.indexOf(comic); + if (position != -1) { + mDataSet.remove(comic); + mDataSet.add(0, comic); + notifyItemMoved(position, 0); + } else { + mDataSet.add(0, comic); + notifyItemInserted(0); + } } public void removeById(long id) { diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/FavoriteAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/FavoriteAdapter.java new file mode 100644 index 00000000..ae658a7c --- /dev/null +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/FavoriteAdapter.java @@ -0,0 +1,69 @@ +package com.hiroshi.cimoc.ui.adapter; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.view.View; + +import com.hiroshi.cimoc.model.MiniComic; + +import java.util.List; + +/** + * Created by Hiroshi on 2016/8/5. + */ +public class FavoriteAdapter extends ComicAdapter { + + public FavoriteAdapter(Context context, List list) { + super(context, list); + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + super.onBindViewHolder(holder, position); + if (mDataSet.get(position).getStatus()) { + ((ViewHolder) holder).comicNew.setVisibility(View.VISIBLE); + } else { + ((ViewHolder) holder).comicNew.setVisibility(View.INVISIBLE); + } + } + + @Override + public void add(MiniComic data) { + super.add(findFirstNormal(), data); + } + + @Override + public void addAll(List data) { + super.addAll(findFirstNormal(), data); + } + + public void updateAll(List list) { + mDataSet.removeAll(list); + mDataSet.addAll(0, list); + notifyDataSetChanged(); + } + + public MiniComic cancelNew(int position) { + MiniComic comic = mDataSet.get(position); + if (comic.getStatus()) { + comic.setStatus(false); + mDataSet.remove(position); + int temp = findFirstNormal(); + mDataSet.add(temp, comic); + notifyItemMoved(position, temp); + } + return comic; + } + + private int findFirstNormal() { + int index = 0; + for (MiniComic comic : mDataSet) { + if (!comic.getStatus()) { + break; + } + ++index; + } + return index; + } + +} diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePagerAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePagerAdapter.java index 7f982ad9..163e7f53 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePagerAdapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePagerAdapter.java @@ -2,10 +2,10 @@ import android.graphics.drawable.Animatable; import android.support.v4.view.PagerAdapter; -import android.view.GestureDetector.SimpleOnGestureListener; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.ImageView; import android.widget.TextView; import com.facebook.drawee.backends.pipeline.PipelineDraweeControllerBuilder; @@ -14,7 +14,6 @@ import com.hiroshi.cimoc.R; import com.hiroshi.cimoc.ui.custom.LimitedViewPager; import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeView; -import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeViewController; import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeViewController.OnSingleTapListener; import java.util.Arrays; @@ -35,32 +34,47 @@ public class PicturePagerAdapter extends PagerAdapter { private LayoutInflater inflater; private OnSingleTapListener listener; private PipelineDraweeControllerBuilder builder; - private int prev; - private int next; + private int left; + private int right; private int pStatus; private int nStatus; + private int current; + public PicturePagerAdapter(List images, LayoutInflater inflater, OnSingleTapListener listener, PipelineDraweeControllerBuilder builder) { this.images = images; this.inflater = inflater; this.listener = listener; this.builder = builder; - this.prev = MAX_COUNT / 2; - this.next = MAX_COUNT / 2 + 1; + this.left = MAX_COUNT / 2; + this.current = MAX_COUNT / 2 + 1; + this.right = MAX_COUNT / 2 + 1; this.pStatus = STATUS_LOAD; this.nStatus = STATUS_LOAD; } + public void setCurrent(int current) { + this.current = current; + } + + public int getCurrent() { + return current; + } + + public int getLeft() { + return left; + } + public void setPrevImages(String[] array) { images.addAll(0, Arrays.asList(array)); - prev -= array.length; + left -= array.length; notifyDataSetChanged(); } public void setNextImages(String[] array) { images.addAll(Arrays.asList(array)); - next += array.length; + right += array.length; notifyDataSetChanged(); } @@ -73,12 +87,12 @@ public void notifySpecialPage(boolean isFirst, int status) { notifyDataSetChanged(); } - public int getLimitByPosition(int position) { - if (prev + 1 == next) { + public int getLimit() { + if (left + 1 == right) { return LimitedViewPager.LIMIT_BOTH; - } else if (position == prev) { + } else if (current == left) { return LimitedViewPager.LIMIT_RIGHT; - } else if (position == next) { + } else if (current == right) { return LimitedViewPager.LIMIT_LEFT; } return LimitedViewPager.LIMIT_NONE; @@ -108,13 +122,13 @@ public void destroyItem(ViewGroup container, int position, Object object) { @Override public Object instantiateItem(ViewGroup container, int position) { View child; - if (position <= prev || position >= next) { + if (position <= left || position >= right) { child = inflater.inflate(R.layout.item_picture_msg, container, false); TextView textView = (TextView) child.findViewById(R.id.picture_msg); int what = STATUS_LOAD; - if (position == prev) { + if (position == left) { what = pStatus; - } else if (position == next) { + } else if (position == right) { what = nStatus; } switch (what) { @@ -131,6 +145,8 @@ public Object instantiateItem(ViewGroup container, int position) { } else { child = inflater.inflate(R.layout.item_picture, container, false); final PhotoDraweeView draweeView = (PhotoDraweeView) child.findViewById(R.id.picture_image_view); + draweeView.setScaleType(ImageView.ScaleType.FIT_CENTER); + draweeView.setHorizontalMode(); draweeView.setOnSingleTapListener(listener); builder.setControllerListener(new BaseControllerListener() { @Override @@ -142,7 +158,7 @@ public void onFinalImageSet(String id, ImageInfo imageInfo, Animatable animatabl draweeView.update(imageInfo.getWidth(), imageInfo.getHeight()); } }).setTapToRetryEnabled(true); - draweeView.setController(builder.setUri(images.get(position - prev - 1)).build()); + draweeView.setController(builder.setUri(images.get(position - left - 1)).build()); child.setTag(POSITION_UNCHANGED); } container.addView(child); diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PictureStreamAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PictureStreamAdapter.java new file mode 100644 index 00000000..e4fdfbb8 --- /dev/null +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PictureStreamAdapter.java @@ -0,0 +1,75 @@ +package com.hiroshi.cimoc.ui.adapter; + +import android.content.Context; +import android.graphics.Rect; +import android.graphics.drawable.Animatable; +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +import com.facebook.drawee.backends.pipeline.PipelineDraweeControllerBuilder; +import com.facebook.drawee.controller.BaseControllerListener; +import com.facebook.imagepipeline.image.ImageInfo; +import com.hiroshi.cimoc.R; +import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeView; + +import java.util.LinkedList; + +import butterknife.BindView; + +/** + * Created by Hiroshi on 2016/8/5. + */ +public class PictureStreamAdapter extends BaseAdapter { + + private PipelineDraweeControllerBuilder builder; + + public PictureStreamAdapter(Context context, PipelineDraweeControllerBuilder builder) { + super(context, new LinkedList()); + this.builder = builder; + } + + public class ViewHolder extends BaseViewHolder { + @BindView(R.id.picture_image_view) PhotoDraweeView photoView; + + public ViewHolder(View view) { + super(view); + } + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view = mInflater.inflate(R.layout.item_picture, parent, false); + return new ViewHolder(view); + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + final PhotoDraweeView draweeView = ((ViewHolder) holder).photoView; + draweeView.setScaleType(ImageView.ScaleType.CENTER_CROP); + draweeView.setVerticalMode(); + builder.setControllerListener(new BaseControllerListener() { + @Override + public void onFinalImageSet(String id, ImageInfo imageInfo, Animatable animatable) { + super.onFinalImageSet(id, imageInfo, animatable); + if (imageInfo != null) { + draweeView.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT; + draweeView.setAspectRatio((float) imageInfo.getWidth() / imageInfo.getHeight()); + draweeView.update(imageInfo.getWidth(), imageInfo.getHeight()); + } + } + }).setTapToRetryEnabled(true); + draweeView.setController(builder.setUri(mDataSet.get(position)).build()); + } + + @Override + public RecyclerView.ItemDecoration getItemDecoration() { + return new RecyclerView.ItemDecoration() { + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + outRect.set(0, 10, 0, 10); + } + }; + } +} diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PreloadAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PreloadAdapter.java index 6447676c..113deb4c 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PreloadAdapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PreloadAdapter.java @@ -2,90 +2,65 @@ import com.hiroshi.cimoc.model.Chapter; +import java.util.List; + /** * Created by Hiroshi on 2016/7/29. */ public class PreloadAdapter { - private Chapter[] array; - private int[] offset; - private int current; - + private List list; private int index; private int prev; private int next; - public PreloadAdapter(Chapter[] array, int index, int current) { - this.array = array; + public PreloadAdapter(List list, int index) { + this.list = list; this.index = index; - this.current = current; - - offset = new int[array.length + 1]; - offset[index] = current; - prev = index - 1; + prev = index + 1; next = index; } public Chapter getPrevChapter() { - return prev >= 0 ? array[prev] : null; + return prev < list.size() ? list.get(prev) : null; } public Chapter getNextChapter() { - return next < array.length ? array[next] : null; + return next >= 0 ? list.get(next) : null; } - public Chapter getValidChapter() { - if (prev < index && index < next) { - return array[index]; + public Chapter prevChapter() { + if (++index < prev) { + return list.get(index); } return null; } - public int getMax() { - return offset[index + 1] - offset[index]; + public Chapter nextChapter() { + if (--index > next) { + return list.get(index); + } + return null; } - public int getValidProgress() { - return current - offset[index] + 1; - } - - public boolean moveToPosition(int position) { - if (current == position) { - return false; - } - current = position; - if (index == -1) { - ++index; - return true; - } - if (index == offset.length - 1) { - --index; - return true; - } - if (position == offset[index] - 1){ - --index; - return true; - } - if (position == offset[index + 1]) { - ++index; - return true; - } - return false; + public Chapter movePrev() { + return list.get(prev++); } - public int getCurrentOffset() { - return offset[index]; + public Chapter moveNext() { + return list.get(next--); } - - public void movePrev(int value) { - offset[prev] = offset[prev + 1] - value; - --prev; + + public int getOffset() { + int offset = 0; + for (int i = prev - 1; i > index; --i) { + offset += list.get(i).getCount(); + } + return offset; } - - public void moveNext(int value) { - offset[next + 1] = offset[next] + value; - ++next; + + public boolean isLoad() { + return index != next; } - } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/PhotoDraweeView.java b/app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/PhotoDraweeView.java index 9f2bd959..62fecfc9 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/PhotoDraweeView.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/PhotoDraweeView.java @@ -64,6 +64,14 @@ public void setOnSingleTapListener(PhotoDraweeViewController.OnSingleTapListener mPhotoDraweeViewController.setOnSingleTapListener(listener); } + public void setHorizontalMode() { + mPhotoDraweeViewController.setHorizontalMode(); + } + + public void setVerticalMode() { + mPhotoDraweeViewController.setVerticalMode(); + } + public void update(int imageInfoWidth, int imageInfoHeight) { mPhotoDraweeViewController.update(imageInfoWidth, imageInfoHeight); } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/PhotoDraweeViewController.java b/app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/PhotoDraweeViewController.java index d7dc6e9c..2904c12d 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/PhotoDraweeViewController.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/PhotoDraweeViewController.java @@ -40,8 +40,13 @@ public interface OnScaleChangeListener { private static final int EDGE_NONE = -1; private static final int EDGE_LEFT = 0; private static final int EDGE_RIGHT = 1; + private static final int EDGE_TOP = 0; + private static final int EDGE_BOTTOM = 1; private static final int EDGE_BOTH = 2; + private static final int MODE_VERTICAL = 0; + private static final int MODE_HORIZONTAL = 1; + private final float[] mMatrixValues = new float[9]; private final RectF mDisplayRect = new RectF(); private final Interpolator mZoomInterpolator = new AccelerateDecelerateInterpolator(); @@ -54,6 +59,7 @@ public interface OnScaleChangeListener { private boolean mBlockParentIntercept = false; private boolean mAllowParentInterceptOnEdge = true; private int mScrollEdge = EDGE_BOTH; + private int mScrollMode = MODE_HORIZONTAL; private final Matrix mMatrix = new Matrix(); private int mImageInfoHeight = -1, mImageInfoWidth = -1; @@ -97,6 +103,14 @@ private void setScale(float scale, float focalX, float focalY, boolean animate) } } + public void setHorizontalMode() { + mScrollMode = MODE_HORIZONTAL; + } + + public void setVerticalMode() { + mScrollMode = MODE_VERTICAL; + } + public void setZoomTransitionDuration(long duration) { duration = duration < 0 ? mZoomDuration : duration; mZoomDuration = duration; @@ -154,7 +168,14 @@ public Matrix getDrawMatrix() { } public RectF getDisplayRect() { - checkMatrixBounds(); + switch (mScrollMode) { + case MODE_HORIZONTAL: + checkHorizontalBounds(); + break; + case MODE_VERTICAL: + checkVerticalBounds(); + break; + } return getDisplayRect(getDrawMatrix()); } @@ -163,12 +184,21 @@ public void checkMatrixAndInvalidate() { if (draweeView == null) { return; } - if (checkMatrixBounds()) { - draweeView.invalidate(); + switch (mScrollMode) { + case MODE_HORIZONTAL: + if (checkHorizontalBounds()) { + draweeView.invalidate(); + } + break; + case MODE_VERTICAL: + if (checkVerticalBounds()) { + draweeView.invalidate(); + } + break; } } - public boolean checkMatrixBounds() { + public boolean checkVerticalBounds() { RectF rect = getDisplayRect(getDrawMatrix()); if (rect == null) { return false; @@ -178,8 +208,45 @@ public boolean checkMatrixBounds() { float width = rect.width(); float deltaX = 0.0F; float deltaY = 0.0F; + int viewHeight = getViewHeight(); + if (height <= viewHeight) { + deltaY = (viewHeight - height) / 2 - rect.top; + mScrollEdge = EDGE_BOTH; + } else if (rect.top > 0) { + deltaY = -rect.top; + mScrollEdge = EDGE_TOP; + } else if (rect.bottom < viewHeight) { + deltaY = viewHeight - rect.bottom; + mScrollEdge = EDGE_BOTTOM; + } else { + mScrollEdge = EDGE_NONE; + } + int viewWidth = getViewWidth(); + if (width <= (float) viewWidth) { + deltaX = (viewWidth - width) / 2 - rect.left; + } else if (rect.left > 0.0F) { + deltaX = -rect.left; + } else if (rect.right < (float) viewWidth) { + deltaX = viewWidth - rect.right; + } + + mMatrix.postTranslate(deltaX, deltaY); + return true; + } + public boolean checkHorizontalBounds() { + RectF rect = getDisplayRect(getDrawMatrix()); + if (rect == null) { + return false; + } + + float height = rect.height(); + float width = rect.width(); + float deltaX = 0.0F; + float deltaY = 0.0F; + + int viewHeight = getViewHeight(); if (height <= (float) viewHeight) { deltaY = (viewHeight - height) / 2 - rect.top; } else if (rect.top > 0.0F) { @@ -225,7 +292,14 @@ private void updateBaseMatrix() { private void resetMatrix() { mMatrix.reset(); - checkMatrixBounds(); + switch (mScrollMode) { + case MODE_HORIZONTAL: + checkHorizontalBounds(); + break; + case MODE_VERTICAL: + checkVerticalBounds(); + break; + } DraweeView draweeView = getDraweeView(); if (draweeView != null) { draweeView.invalidate(); @@ -311,10 +385,21 @@ private void checkMinScale() { if (mAllowParentInterceptOnEdge && !mScaleDragDetector.isScaling() && !mBlockParentIntercept) { - if (mScrollEdge == EDGE_BOTH || (mScrollEdge == EDGE_LEFT && dx >= 1f) || ( - mScrollEdge == EDGE_RIGHT - && dx <= -1f)) { - parent.requestDisallowInterceptTouchEvent(false); + switch (mScrollMode) { + case MODE_HORIZONTAL: + if (mScrollEdge == EDGE_BOTH || (mScrollEdge == EDGE_LEFT && dx >= 1f) || ( + mScrollEdge == EDGE_RIGHT + && dx <= -1f)) { + parent.requestDisallowInterceptTouchEvent(false); + } + break; + case MODE_VERTICAL: + if (mScrollEdge == EDGE_BOTH || (mScrollEdge == EDGE_TOP && dy >= 1f) || ( + mScrollEdge == EDGE_BOTTOM + && dy <= -1f)) { + parent.requestDisallowInterceptTouchEvent(false); + } + break; } } else { parent.requestDisallowInterceptTouchEvent(true); diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/AboutFragment.java b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/AboutFragment.java index 3685aae8..a49bf001 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/AboutFragment.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/AboutFragment.java @@ -1,7 +1,5 @@ package com.hiroshi.cimoc.ui.fragment; -import android.support.design.widget.Snackbar; - import com.hiroshi.cimoc.CimocApplication; import com.hiroshi.cimoc.R; import com.hiroshi.cimoc.presenter.BasePresenter; @@ -21,10 +19,7 @@ public class AboutFragment extends BaseFragment { if (++count > 9) { isEnable = !isEnable; CimocApplication.getPreferences().putBoolean(PreferenceMaster.PREF_EX, isEnable); - if (getView() != null) { - String msg = isEnable ? "重启软件开启 EHentai" : "重启软件关闭 EHentai"; - Snackbar.make(getView(), msg, Snackbar.LENGTH_SHORT).show(); - } + showSnackbar(isEnable ? "重启软件开启 EHentai" : "重启软件关闭 EHentai"); count = 0; } } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/BaseFragment.java b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/BaseFragment.java index 8f0ee389..4e2948d6 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/BaseFragment.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/BaseFragment.java @@ -4,6 +4,7 @@ import android.os.Bundle; import android.support.annotation.LayoutRes; import android.support.annotation.Nullable; +import android.support.design.widget.Snackbar; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -38,6 +39,12 @@ public void onDestroy() { } } + public void showSnackbar(String msg) { + if (getView() != null) { + Snackbar.make(getView(), msg, Snackbar.LENGTH_SHORT).show(); + } + } + protected abstract void initView(); protected abstract @LayoutRes int getLayoutView(); diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/CimocFragment.java b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/CimocFragment.java index a2317ff1..03bd3fa8 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/CimocFragment.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/CimocFragment.java @@ -45,12 +45,13 @@ public class CimocFragment extends BaseFragment { } @OnLongClick(R.id.main_search_btn) boolean onLongClick() { - DialogFactory.buildSingleChoiceDialog(getActivity(), "图源选择", array, choice, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - choice = which; - } - }, null).show(); + DialogFactory.buildSingleChoiceDialog(getActivity(), R.string.cimoc_select_source, array, choice, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + choice = which; + } + }, null).show(); return true; } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/FavoriteFragment.java b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/FavoriteFragment.java index 4b29127e..295bc627 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/FavoriteFragment.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/FavoriteFragment.java @@ -8,7 +8,6 @@ import android.os.Build; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; -import android.util.Log; import android.view.View; import com.hiroshi.cimoc.R; @@ -18,7 +17,7 @@ import com.hiroshi.cimoc.presenter.BasePresenter; import com.hiroshi.cimoc.presenter.FavoritePresenter; import com.hiroshi.cimoc.ui.adapter.BaseAdapter; -import com.hiroshi.cimoc.ui.adapter.ComicAdapter; +import com.hiroshi.cimoc.ui.adapter.FavoriteAdapter; import com.hiroshi.cimoc.utils.DialogFactory; import java.util.LinkedList; @@ -34,7 +33,7 @@ public class FavoriteFragment extends BaseFragment { @BindView(R.id.favorite_comic_list) RecyclerView mRecyclerView; - private ComicAdapter mComicAdapter; + private FavoriteAdapter mFavoriteAdapter; private FavoritePresenter mPresenter; private Notification.Builder mBuilder; private NotificationManager mManager; @@ -46,36 +45,46 @@ protected void initView() { isChecking = false; mManager = (NotificationManager) getActivity().getSystemService(Context.NOTIFICATION_SERVICE); mBuilder = new Notification.Builder(getActivity()); - mComicAdapter = new ComicAdapter(getActivity(), mPresenter.getComicList()); - mComicAdapter.setOnItemClickListener(new BaseAdapter.OnItemClickListener() { + mFavoriteAdapter = new FavoriteAdapter(getActivity(), mPresenter.getComicList()); + mFavoriteAdapter.setOnItemClickListener(new BaseAdapter.OnItemClickListener() { @Override public void onItemClick(View view, int position) { - mPresenter.onItemClick(mComicAdapter.getItem(position)); + MiniComic comic = mFavoriteAdapter.cancelNew(position); + mPresenter.onItemClick(comic); } }); - mComicAdapter.setOnItemLongClickListener(new BaseAdapter.OnItemLongClickListener() { + mFavoriteAdapter.setOnItemLongClickListener(new BaseAdapter.OnItemLongClickListener() { @Override public void onItemLongClick(View view, final int position) { - DialogFactory.buildPositiveDialog(getActivity(), "删除提示", "是否删除该收藏", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - mPresenter.onPositiveClick(mComicAdapter.getItem(position)); - mComicAdapter.remove(position); - } - }).show(); + DialogFactory.buildPositiveDialog(getActivity(), R.string.dialog_confirm, R.string.favorite_delete_confirm, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + mPresenter.onPositiveClick(mFavoriteAdapter.getItem(position)); + mFavoriteAdapter.remove(position); + } + }).show(); } }); mRecyclerView.setItemAnimator(null); mRecyclerView.setLayoutManager(new GridLayoutManager(getActivity(), 3)); - mRecyclerView.setAdapter(mComicAdapter); - mRecyclerView.addItemDecoration(mComicAdapter.getItemDecoration()); + mRecyclerView.setAdapter(mFavoriteAdapter); + mRecyclerView.addItemDecoration(mFavoriteAdapter.getItemDecoration()); } @OnClick(R.id.favorite_check_btn) void onCheckClick() { if (!isChecking) { - isChecking = true; - UpdateTask task = new UpdateTask(); - task.execute(mPresenter.getComicArray()); + DialogFactory.buildPositiveDialog(getActivity(), R.string.dialog_confirm, R.string.favorite_update_confirm, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + isChecking = true; + UpdateTask task = new UpdateTask(); + task.execute(mPresenter.getComicArray()); + } + }).show(); + } else { + showSnackbar("正在检查更新中"); } } @@ -95,15 +104,15 @@ protected void initPresenter() { } public void addItem(MiniComic comic) { - mComicAdapter.add(0, comic); + mFavoriteAdapter.add(0, comic); } public void removeItem(long id) { - mComicAdapter.removeById(id); + mFavoriteAdapter.removeById(id); } public void addItems(List list) { - mComicAdapter.addAll(0, list); + mFavoriteAdapter.addAll(0, list); } class UpdateTask extends AsyncTask> { @@ -115,11 +124,7 @@ protected void onPreExecute() { .setTicker("正在检查更新") .setOngoing(true) .setProgress(0, 0, true); - if (Build.VERSION.SDK_INT >= 16) { - mManager.notify(1, mBuilder.build()); - } else { - mManager.notify(1, mBuilder.getNotification()); - } + notifyBuilder(); } @Override @@ -135,6 +140,7 @@ protected List doInBackground(MiniComic... params) { String update = manga.check(comic.getCid()); if (update != null && !comic.getUpdate().equals(update)) { comic.setUpdate(update); + comic.setStatus(true); list.add(comic); } publishProgress(count++, params.length); @@ -144,31 +150,29 @@ protected List doInBackground(MiniComic... params) { @Override protected void onProgressUpdate(Integer... values) { - Log.e("----------", "------" + values[0] + "---" + values[1]); - mBuilder.setProgress(values[1], values[0], false) - .setTicker(null); - if (Build.VERSION.SDK_INT >= 16) { - mManager.notify(1, mBuilder.build()); - } else { - mManager.notify(1, mBuilder.getNotification()); - } + mBuilder.setProgress(values[1], values[0], false); + notifyBuilder(); } @Override protected void onPostExecute(List list) { - //mPresenter.updateComic(list); + mPresenter.updateComic(list); + mFavoriteAdapter.updateAll(list); mBuilder.setOngoing(false) .setTicker(null) .setContentText("检查完成") .setProgress(0, 0, false); - if (Build.VERSION.SDK_INT >= 16) { - mManager.notify(1, mBuilder.build()); - } else { - mManager.notify(1, mBuilder.getNotification()); - } + notifyBuilder(); isChecking = false; } } + private void notifyBuilder() { + if (Build.VERSION.SDK_INT >= 16) { + mManager.notify(1, mBuilder.build()); + } else { + mManager.notify(1, mBuilder.getNotification()); + } + } } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/HistoryFragment.java b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/HistoryFragment.java index cb43df29..8728e387 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/HistoryFragment.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/HistoryFragment.java @@ -2,7 +2,6 @@ import android.content.DialogInterface; import android.support.v7.app.AlertDialog; -import android.support.v7.widget.DefaultItemAnimator; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; @@ -16,6 +15,7 @@ import com.hiroshi.cimoc.utils.DialogFactory; import butterknife.BindView; +import butterknife.OnClick; /** * Created by Hiroshi on 2016/7/1. @@ -26,9 +26,11 @@ public class HistoryFragment extends BaseFragment { private ComicAdapter mComicAdapter; private HistoryPresenter mPresenter; + private AlertDialog mProgressDialog; @Override protected void initView() { + mProgressDialog = DialogFactory.buildCancelableFalseDialog(getActivity()); mComicAdapter = new ComicAdapter(getActivity(), mPresenter.getComic()); mComicAdapter.setOnItemClickListener(new BaseAdapter.OnItemClickListener() { @Override @@ -39,13 +41,14 @@ public void onItemClick(View view, int position) { mComicAdapter.setOnItemLongClickListener(new BaseAdapter.OnItemLongClickListener() { @Override public void onItemLongClick(View view, final int position) { - DialogFactory.buildPositiveDialog(getActivity(), "删除提示", "是否删除该历史纪录", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - mPresenter.onPositiveClick(mComicAdapter.getItem(position)); - mComicAdapter.remove(position); - } - }).show(); + DialogFactory.buildPositiveDialog(getActivity(), R.string.dialog_confirm, R.string.history_delete_confirm, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + mPresenter.onPositiveClick(mComicAdapter.getItem(position)); + mComicAdapter.remove(position); + } + }).show(); } }); mRecyclerView.setItemAnimator(null); @@ -54,6 +57,18 @@ public void onClick(DialogInterface dialog, int which) { mRecyclerView.addItemDecoration(mComicAdapter.getItemDecoration()); } + @OnClick(R.id.history_clear_btn) void onHistoryClearClick() { + DialogFactory.buildPositiveDialog(getActivity(), R.string.dialog_confirm, R.string.history_clear_confirm, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + mProgressDialog.setMessage("正在删除..."); + mProgressDialog.show(); + mPresenter.onHistoryClearClick(); + } + }).show(); + } + @Override protected BasePresenter getPresenter() { return mPresenter; @@ -77,4 +92,8 @@ public void clearItem() { mComicAdapter.clear(); } + public void hideProgressDialog() { + mProgressDialog.hide(); + } + } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SettingsFragment.java b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SettingsFragment.java index 8d62eff5..f9990699 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SettingsFragment.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SettingsFragment.java @@ -2,7 +2,6 @@ import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; -import android.support.design.widget.Snackbar; import android.support.v7.app.AlertDialog; import android.widget.TextView; @@ -31,7 +30,7 @@ public class SettingsFragment extends BaseFragment { @Override protected void initView() { - mProgressDialog = new AlertDialog.Builder(getActivity(), R.style.AppTheme_Dialog_Alert).setCancelable(false).create(); + mProgressDialog = DialogFactory.buildCancelableFalseDialog(getActivity()); mHomeChoice = CimocApplication.getPreferences().getInt(PreferenceMaster.PREF_HOME, R.id.drawer_cimoc); mIndexSummary.setText(PreferenceMaster.getTitleById(mHomeChoice)); } @@ -42,7 +41,7 @@ protected void initView() { showSnackbar("没有找到备份文件"); return; } - DialogFactory.buildSingleChoiceDialog(getActivity(), "选择文件", array, -1, + DialogFactory.buildSingleChoiceDialog(getActivity(), R.string.settings_select_file, array, -1, new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { @@ -59,7 +58,7 @@ public void onClick(DialogInterface dialog, int which) { @OnClick(R.id.settings_other_home_btn) void onHomeBtnClick() { final int[] array = new int[] { R.id.drawer_cimoc, R.id.drawer_favorite, R.id.drawer_history }; - DialogFactory.buildSingleChoiceDialog(getActivity(), "首页选择", R.array.index_items, -1, + DialogFactory.buildSingleChoiceDialog(getActivity(), R.string.settings_select_home, R.array.index_items, -1, new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { @@ -83,16 +82,6 @@ public void onClick(DialogInterface dialog, int which) { mPresenter.onCacheBtnClick(); } - @OnClick(R.id.settings_other_history_btn) void onHistoryBtnClick() { - mPresenter.onHistoryBtnClick(); - } - - @Override - public void onDestroy() { - super.onDestroy(); - mProgressDialog.dismiss(); - } - @Override protected void initPresenter() { mPresenter = new SettingsPresenter(this); @@ -117,12 +106,4 @@ public void hideProgressDialog() { mProgressDialog.hide(); } - public void showSnackbar(String msg) { - if (getView() != null) { - Snackbar.make(getView(), msg, Snackbar.LENGTH_SHORT).show(); - } - } - - - } diff --git a/app/src/main/java/com/hiroshi/cimoc/utils/DialogFactory.java b/app/src/main/java/com/hiroshi/cimoc/utils/DialogFactory.java index 27158db7..94d56020 100644 --- a/app/src/main/java/com/hiroshi/cimoc/utils/DialogFactory.java +++ b/app/src/main/java/com/hiroshi/cimoc/utils/DialogFactory.java @@ -6,34 +6,40 @@ import com.hiroshi.cimoc.R; +import butterknife.OnClick; + /** * Created by Hiroshi on 2016/8/4. */ public class DialogFactory { - public static AlertDialog buildPositiveDialog(Context context, String title, String message, OnClickListener listener) { + public static AlertDialog buildPositiveDialog(Context context, int titleId, int messageId, OnClickListener listener) { AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.AppTheme_Dialog_Alert); - builder.setTitle(title); - builder.setMessage(message); - builder.setPositiveButton("确定", listener); - builder.setNegativeButton("取消", null); + builder.setTitle(titleId); + builder.setMessage(messageId); + builder.setPositiveButton(R.string.dialog_positive, listener); + builder.setNegativeButton(R.string.dialog_negative, null); return builder.create(); } - public static AlertDialog buildSingleChoiceDialog(Context context, String title, int array, int choice, + public static AlertDialog buildSingleChoiceDialog(Context context, int titleId, int array, int choice, OnClickListener listener, OnClickListener positive) { - return buildSingleChoiceDialog(context, title, context.getResources().getStringArray(array), choice, listener, positive); + return buildSingleChoiceDialog(context, titleId, context.getResources().getStringArray(array), choice, listener, positive); } - public static AlertDialog buildSingleChoiceDialog(Context context, String title, String[] array, int choice, + public static AlertDialog buildSingleChoiceDialog(Context context, int titleId, String[] array, int choice, OnClickListener listener, OnClickListener positive) { AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.AppTheme_Dialog_Alert); - builder.setTitle(title); + builder.setTitle(titleId); builder.setSingleChoiceItems(array, choice, listener); if (positive != null) { - builder.setPositiveButton("确定", positive); + builder.setPositiveButton(R.string.dialog_positive, positive); } return builder.create(); } + public static AlertDialog buildCancelableFalseDialog(Context context) { + return new AlertDialog.Builder(context, R.style.AppTheme_Dialog_Alert).setCancelable(false).create(); + } + } diff --git a/app/src/main/res/drawable-hdpi/ic_delete_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_delete_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..4a9f769475ae98c44086a5498057c799cdc1eb2e GIT binary patch literal 161 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K8hNp{Th{y5d1PNA=hW|4Ewf~tb z9PIip^F(s-FKmRW+J}dc&f#K)gg?ihMxz_^iWbkzL Kb6Mw<&;$SheLUU( literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_delete_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_delete_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..388b5b060af924493b057a63216fe7db75d4435a GIT binary patch literal 151 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}b0DI8PVHkch)?FC64-Fko=L=%?Iw zv$u;+&1tXu2b~*Nwk`N$?;xkbvPe<$)w&zy|9BUkVz|Zlf5mTGpk6SDXXMMa|9v2f u@g#fN+oPXnt4Z(ZaQ*pHX6dTRMUVWXo;a(XeY#{ZNU5i*pUXO@geCyi%r-Ls literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_delete_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_delete_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..3fcdfdb55ebcba8d2fff8be03ea3518c137e3464 GIT binary patch literal 194 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhawIz3$+Lo)8Yy>yn>!GXc$q3uOx zabB)cz0QC}ts}W53MuVBD%UsZPv&gw=#W`?Y0ciWQ2$4FyseJx>{`Oj#KIv^yWsd< zb^!&41_nkD7m4wnX|34#N6cTv0=_gxaj*E+Smb+hj$`D9r9sI`%Q@~%Ssl3i>7S{h gq0!eBm41aw^UfFNx4vv@4|EiRr>mdKI;Vst0RDqR&j0`b literal 0 HcmV?d00001 diff --git a/app/src/main/res/layout/activity_reader.xml b/app/src/main/res/layout/activity_reader.xml index 99065f37..5a6f3581 100644 --- a/app/src/main/res/layout/activity_reader.xml +++ b/app/src/main/res/layout/activity_reader.xml @@ -18,7 +18,7 @@ android:paddingBottom="2dp" android:paddingLeft="6dp" android:paddingRight="6dp" - android:background="@color/trans_light_grey"> + android:background="@color/trans_light_black"> + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_history.xml b/app/src/main/res/layout/fragment_history.xml index d1e86629..50d7265f 100644 --- a/app/src/main/res/layout/fragment_history.xml +++ b/app/src/main/res/layout/fragment_history.xml @@ -1,9 +1,23 @@ - \ No newline at end of file + android:layout_height="match_parent"> + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml index 67a72a10..cfa6d27e 100644 --- a/app/src/main/res/layout/fragment_settings.xml +++ b/app/src/main/res/layout/fragment_settings.xml @@ -103,7 +103,7 @@ android:textSize="14sp"/> + android:text="@string/settings_other_mode"/> + android:text="@string/settings_other_cache"/> #BEBEBE #AAFFC107 - #3FBEBEBE + #4F000000 #AABEBEBE #CC000000 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ed5d3ab8..39377b53 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -20,6 +20,14 @@ 前面没有了 :( + 图源选择 + + 是否删除该漫画 + 是否检查更新 + + 是否删除该历史纪录 + 是否清除所有历史纪录 + NEW version: 1.1.0 @@ -31,9 +39,17 @@ 从本地文件中恢复 其他设置 首页设置 - 清除历史纪录 清除缓存 + 阅读模式 + + 首页选择 + 文件选择 源代码 https://github.com/Arachnid-27/Cimoc + + 操作确认 + 确定 + 取消 + From be8669c0dbd4fe228af38e7e617e5fb3027ca1bb Mon Sep 17 00:00:00 2001 From: hiroshi Date: Sun, 7 Aug 2016 01:17:48 +0800 Subject: [PATCH 004/521] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=BF=BB=E9=A1=B5?= =?UTF-8?q?=E9=98=85=E8=AF=BB=E7=9A=84=E5=AE=9E=E7=8E=B0=20=E6=9B=BF?= =?UTF-8?q?=E6=8D=A2E=E7=BB=85=E5=A3=AB=E5=9B=BE=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/dictionaries/Hiroshi.xml | 1 + .idea/misc.xml | 2 +- app/src/main/AndroidManifest.xml | 2 +- .../com/hiroshi/cimoc/core/ComicManager.java | 114 +------- .../java/com/hiroshi/cimoc/core/ExHentai.java | 110 +++++++ .../java/com/hiroshi/cimoc/core/Kami.java | 12 +- .../com/hiroshi/cimoc/model/EventMessage.java | 7 +- .../cimoc/presenter/DetailPresenter.java | 95 +++--- .../cimoc/presenter/MainPresenter.java | 17 +- .../cimoc/presenter/ReaderPresenter.java | 124 ++++---- .../cimoc/presenter/ResultPresenter.java | 23 +- .../presenter/StreamReaderPresenter.java | 49 ++-- .../cimoc/ui/activity/BaseActivity.java | 35 ++- .../cimoc/ui/activity/DetailActivity.java | 96 +++--- .../cimoc/ui/activity/MainActivity.java | 42 +-- .../cimoc/ui/activity/PageReaderActivity.java | 223 ++++++++++++++ .../cimoc/ui/activity/ReaderActivity.java | 192 +++--------- .../cimoc/ui/activity/ResultActivity.java | 36 ++- .../ui/activity/StreamReaderActivity.java | 67 +++-- .../hiroshi/cimoc/ui/adapter/BaseAdapter.java | 4 + .../cimoc/ui/adapter/ChapterAdapter.java | 9 +- .../cimoc/ui/adapter/FavoriteAdapter.java | 1 + ...erAdapter.java => PicturePageAdapter.java} | 68 +---- .../cimoc/ui/adapter/PreloadAdapter.java | 30 +- .../cimoc/ui/custom/LimitedViewPager.java | 18 ++ .../cimoc/ui/fragment/AboutFragment.java | 8 - .../cimoc/ui/fragment/BaseFragment.java | 13 +- .../cimoc/ui/fragment/CimocFragment.java | 9 - .../cimoc/ui/fragment/SettingsFragment.java | 57 +++- .../cimoc/utils/ControllerBuilderFactory.java | 13 +- .../hiroshi/cimoc/utils/DialogFactory.java | 2 - .../com/hiroshi/cimoc/utils/MachiSoup.java | 13 +- .../hiroshi/cimoc/utils/PreferenceMaster.java | 27 +- app/src/main/res/layout/fragment_settings.xml | 276 +++++++++++------- app/src/main/res/layout/item_comic.xml | 1 + app/src/main/res/values/arrays.xml | 9 +- app/src/main/res/values/strings.xml | 6 +- 37 files changed, 1031 insertions(+), 780 deletions(-) create mode 100644 app/src/main/java/com/hiroshi/cimoc/core/ExHentai.java create mode 100644 app/src/main/java/com/hiroshi/cimoc/ui/activity/PageReaderActivity.java rename app/src/main/java/com/hiroshi/cimoc/ui/adapter/{PicturePagerAdapter.java => PicturePageAdapter.java} (62%) diff --git a/.idea/dictionaries/Hiroshi.xml b/.idea/dictionaries/Hiroshi.xml index fc2136d2..805a85ae 100644 --- a/.idea/dictionaries/Hiroshi.xml +++ b/.idea/dictionaries/Hiroshi.xml @@ -3,6 +3,7 @@ cctuku chuiyao + exhentai kami machi manhua diff --git a/.idea/misc.xml b/.idea/misc.xml index 5d199810..fbb68289 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -37,7 +37,7 @@ - + diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e618bded..4be82430 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -30,7 +30,7 @@ android:screenOrientation="portrait"/> diff --git a/app/src/main/java/com/hiroshi/cimoc/core/ComicManager.java b/app/src/main/java/com/hiroshi/cimoc/core/ComicManager.java index 8e52e0ef..73781929 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/ComicManager.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/ComicManager.java @@ -3,7 +3,6 @@ import android.database.Cursor; import com.hiroshi.cimoc.CimocApplication; -import com.hiroshi.cimoc.model.Chapter; import com.hiroshi.cimoc.model.Comic; import com.hiroshi.cimoc.model.ComicDao; import com.hiroshi.cimoc.model.ComicDao.Properties; @@ -65,7 +64,7 @@ public void updateFavorite(final List list) { public void run() { for (MiniComic comic : list) { Comic temp = mComicDao.load(comic.getId()); - if (temp != null) { + if (temp != null && !comic.getUpdate().equals(temp.getUpdate())) { temp.setUpdate(comic.getUpdate()); temp.setFavorite(NEW_VALUE); mComicDao.update(temp); @@ -171,12 +170,8 @@ private List listByCursor(Cursor cursor) { return list; } - private Comic comic; - private List chapters; - private boolean isHistory; - - public void setComic(Long id, int source, String cid) { - isHistory = false; + public Comic getComic(Long id, int source, String cid) { + Comic comic; if (id == null) { comic = mComicDao.queryBuilder() .where(Properties.Source.eq(source), Properties.Cid.eq(cid)) @@ -190,106 +185,23 @@ public void setComic(Long id, int source, String cid) { if (comic == null) { comic = new Comic(source, cid); } - ExLog.d("ComicManager", "init id = " + comic.getId() + " source = " + comic.getSource() + " cid = " + comic.getCid()); - } - - public void setChapters(List chapters) { - this.chapters = chapters; - ExLog.d("ComicManager", "set chapter list and the number is " + chapters.size()); - } - - public void setLast(String path) { - comic.setLast(path); - comic.setPage(1); - comic.setHistory(System.currentTimeMillis()); - if (!isComicExist()) { - long id = mComicDao.insert(comic); - comic.setId(id); - ExLog.d("ComicManager", "insert " + comic.getTitle() + " to " + comic.getId()); - } - if (!isHistory) { - EventBus.getDefault().post(new EventMessage(EventMessage.HISTORY_COMIC, new MiniComic(comic))); - isHistory = true; - } - ExLog.d("ComicManager", "set the last path of" + " [" + comic.getId() + "] " + comic.getTitle() + " to " + path); - } - - public void afterRead(int page) { - comic.setPage(page); - ExLog.d("ComicManager", "set the last page of" + " [" + comic.getId() + "] " + comic.getTitle() + " to " + page); - EventBus.getDefault().post(new EventMessage(EventMessage.AFTER_READ, comic.getLast())); - } - - public void favoriteComic() { - comic.setFavorite(System.currentTimeMillis()); - if (!isComicExist()) { - long id = mComicDao.insert(comic); - comic.setId(id); - ExLog.d("ComicManager", "insert " + comic.getTitle() + " to " + comic.getId()); - } - ExLog.d("ComicManager", "favorite" + " [" + comic.getId() + "] " + comic.getTitle()); - EventBus.getDefault().post(new EventMessage(EventMessage.FAVORITE_COMIC, new MiniComic(comic))); - } - - public void unfavoriteComic() { - long id = comic.getId(); - comic.setFavorite(null); - if (!isComicHistory()) { - mComicDao.delete(comic); - comic.setId(null); - ExLog.d("ComicManager", "delete" + " [" + id + "] " + comic.getTitle()); - } - ExLog.d("ComicManager", "unfavorite" + " [" + id + "] " + comic.getTitle()); - EventBus.getDefault().post(new EventMessage(EventMessage.UN_FAVORITE_COMIC, id)); - } - - public List getChapters() { - return chapters; - } - - public Comic getComic() { return comic; } - public boolean isComicStar() { - return comic.getFavorite() != null; - } - - public boolean isComicHistory() { - return comic.getHistory() != null; - } - - public boolean isComicExist() { - return comic.getId() != null; - } - - public int getSource() { - return comic.getSource(); - } - - public String getCid() { - return comic.getCid(); - } - - public String getLast() { - return comic.getLast(); + public void updateComic(Comic comic) { + mComicDao.update(comic); + ExLog.d("ComicManager", "update" + " [" + comic.getId() + "] " + comic.getTitle()); } - public int getPage() { - Integer page = comic.getPage(); - if (page == null) { - return -1; - } - return page; + public void deleteComic(long id) { + mComicDao.deleteByKey(id); + ExLog.d("ComicManager", "delete" + " [" + id + "]"); } - public void saveComic() { - if (isComicExist()) { - ExLog.d("ComicManager", "save" + " [" + comic.getId() + "] " + comic.getTitle()); - mComicDao.update(comic); - } - comic = null; - ExLog.d("ComicManager", "clear comic"); + public long insertComic(Comic comic) { + long id = mComicDao.insert(comic); + ExLog.d("ComicManager", "insert" + " [" + id + "] " + comic.getTitle()); + return id; } public static ComicManager getInstance() { diff --git a/app/src/main/java/com/hiroshi/cimoc/core/ExHentai.java b/app/src/main/java/com/hiroshi/cimoc/core/ExHentai.java new file mode 100644 index 00000000..7dd464ad --- /dev/null +++ b/app/src/main/java/com/hiroshi/cimoc/core/ExHentai.java @@ -0,0 +1,110 @@ +package com.hiroshi.cimoc.core; + +import com.hiroshi.cimoc.core.base.Manga; +import com.hiroshi.cimoc.model.Chapter; +import com.hiroshi.cimoc.model.Comic; +import com.hiroshi.cimoc.utils.MachiSoup; +import com.hiroshi.cimoc.utils.MachiSoup.Node; + +import java.util.LinkedList; +import java.util.List; + +import okhttp3.Request; + +/** + * Created by Hiroshi on 2016/8/6. + */ +public class ExHentai extends Manga { + + public ExHentai() { + super(Kami.SOURCE_EHENTAI, "https://exhentai.org"); + } + + @Override + protected Request buildSearchRequest(String keyword, int page) { + String url = host + "?f_search=" + keyword + "&page=" + (page - 1); + return new Request.Builder().url(url).header("Cookie", "ipb_member_id=2145630; ipb_pass_hash=f883b5a9dd10234c9323957b96efbd8e").build(); + } + + @Override + protected List parseSearch(String html) { + Node body = MachiSoup.body(html); + List list = new LinkedList<>(); + for (Node node : body.list("table.itg > tbody > tr[class^=gtr]")) { + String cid = node.attr("td:eq(2) > div > div:eq(2) > a", "href"); + cid = cid.substring(host.length() + 3, cid.length() - 1); + String title = node.text("td:eq(2) > div > div:eq(2) > a"); + String cover = node.attr("td:eq(2) > div > div:eq(0) > img", "src"); + if (cover == null) { + String temp = node.text("td:eq(2) > div > div:eq(0)", 19).split("~", 2)[0]; + cover = host + "/" + temp; + } + String update = node.text("td:eq(1)", 0, 10); + String author = node.text("td:eq(3) > div > a"); + list.add(new Comic(source, cid, title, cover, update, author, true)); + } + return list; + } + + @Override + protected Request buildIntoRequest(String cid) { + String url = host + "/g/" + cid; + return new Request.Builder().url(url).header("Cookie", "s=485adc1edc9d59a6a7d62cd15d1a7a213b333f5cb092bcc2d30c476419fbcb5555f19e27c606df9cdc56737cb920fe0855e9671c7109069401d8ede5b718f522; ipb_member_id=2145630; ipb_pass_hash=f883b5a9dd10234c9323957b96efbd8e; uconfig=ts_l;").build(); + } + + @Override + protected List parseInto(String html, Comic comic) { + List list = new LinkedList<>(); + Node body = MachiSoup.body(html); + String length = body.text("#gdd > table > tbody > tr:eq(5) > td:eq(1)", " ", 0); + int size = Integer.parseInt(length) % 20 == 0 ? Integer.parseInt(length) / 20 : Integer.parseInt(length) / 20 + 1; + for (int i = 0; i != size; ++i) { + list.add(0, new Chapter("Ch" + i, String.valueOf(i))); + } + + String update = body.text("#gdd > table > tbody > tr:eq(0) > td:eq(1)", 0, 10); + String title = body.text("#gn"); + String intro = body.text("#gj"); + String author = body.text("#taglist > table > tbody > tr > td:eq(1) > div > a[id^=ta_artist]"); + String cover = body.attr("#gd1 > img", "src"); + comic.setInfo(title, cover, update, intro, author, true); + + return list; + } + + @Override + protected Request buildBrowseRequest(String cid, String path) { + String url = host + "/g/" + cid + "?p=" + path; + return new Request.Builder().url(url).header("Cookie", "s=485adc1edc9d59a6a7d62cd15d1a7a213b333f5cb092bcc2d30c476419fbcb5555f19e27c606df9cdc56737cb920fe0855e9671c7109069401d8ede5b718f522; ipb_member_id=2145630; ipb_pass_hash=f883b5a9dd10234c9323957b96efbd8e; uconfig=ts_l").build(); + } + + @Override + protected String[] parseBrowse(String html) { + Node body = MachiSoup.body(html); + List list = body.list("#gdt > div > a"); + String[] array = new String[list.size()]; + for (int i = 0; i != array.length; ++i) { + String url = list.get(i).attr("href"); + Request request = new Request.Builder().url(url).header("Cookie", "ipb_member_id=2145630; ipb_pass_hash=f883b5a9dd10234c9323957b96efbd8e").build(); + String result = execute(request); + if (result != null) { + MachiSoup.Node node = MachiSoup.body(result); + array[i] = node.attr("#img", "src"); + } else { + array[i] = null; + } + } + return array; + } + + @Override + protected Request buildCheckRequest(String cid) { + return null; + } + + @Override + protected String parseCheck(String html) { + return null; + } + +} diff --git a/app/src/main/java/com/hiroshi/cimoc/core/Kami.java b/app/src/main/java/com/hiroshi/cimoc/core/Kami.java index 63cc6bb2..0290391c 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/Kami.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/Kami.java @@ -25,7 +25,7 @@ public static String getSourceById(int id) { case SOURCE_CCTUKU: return "CC图库"; case SOURCE_EHENTAI: - return "E-Hentai"; + return "ExHentai"; } } @@ -41,11 +41,11 @@ public static String getRefererById(int id) { case SOURCE_CCTUKU: return "http://m.tuku.cc"; case SOURCE_EHENTAI: - return "http://lofi.e-hentai.org"; + return "https://exhentai.org"; } } - private static Manga mIkanman, mDmzj, mHHAAZZ, mCCTuku, mEHentai; + private static Manga mIkanman, mDmzj, mHHAAZZ, mCCTuku, mExHentai; public static Manga getMangaById(int id) { switch (id) { @@ -71,10 +71,10 @@ public static Manga getMangaById(int id) { } return mCCTuku; case SOURCE_EHENTAI: - if (mEHentai == null) { - mEHentai = new EHentai(); + if (mExHentai == null) { + mExHentai = new ExHentai(); } - return mEHentai; + return mExHentai; } } diff --git a/app/src/main/java/com/hiroshi/cimoc/model/EventMessage.java b/app/src/main/java/com/hiroshi/cimoc/model/EventMessage.java index 350f8062..18f5171e 100644 --- a/app/src/main/java/com/hiroshi/cimoc/model/EventMessage.java +++ b/app/src/main/java/com/hiroshi/cimoc/model/EventMessage.java @@ -15,9 +15,10 @@ public class EventMessage { public static final int FAVORITE_COMIC = 8; public static final int UN_FAVORITE_COMIC = 9; public static final int HISTORY_COMIC = 10; - public static final int AFTER_READ = 11; - public static final int DELETE_HISTORY = 12; - public static final int RESTORE_FAVORITE = 13; + public static final int COMIC_PAGE_CHANGE = 11; + public static final int COMIC_LAST_CHANGE = 12; + public static final int DELETE_HISTORY = 13; + public static final int RESTORE_FAVORITE = 14; private int type; private Object data; diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/DetailPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/DetailPresenter.java index 63867cc5..45857d85 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/DetailPresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/DetailPresenter.java @@ -1,17 +1,15 @@ package com.hiroshi.cimoc.presenter; -import android.content.Intent; - -import com.hiroshi.cimoc.R; import com.hiroshi.cimoc.core.ComicManager; import com.hiroshi.cimoc.core.Kami; import com.hiroshi.cimoc.core.base.Manga; import com.hiroshi.cimoc.model.Chapter; -import com.hiroshi.cimoc.ui.activity.DetailActivity; -import com.hiroshi.cimoc.ui.activity.ReaderActivity; +import com.hiroshi.cimoc.model.Comic; import com.hiroshi.cimoc.model.EventMessage; -import com.hiroshi.cimoc.ui.activity.StreamReaderActivity; +import com.hiroshi.cimoc.model.MiniComic; +import com.hiroshi.cimoc.ui.activity.DetailActivity; +import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; @@ -26,77 +24,86 @@ public class DetailPresenter extends BasePresenter { private DetailActivity mDetailActivity; private ComicManager mComicManager; private Manga mManga; + private Comic mComic; + - public DetailPresenter(DetailActivity activity) { + public DetailPresenter(DetailActivity activity, Long id, int source, String cid) { mDetailActivity = activity; mComicManager = ComicManager.getInstance(); - mManga = Kami.getMangaById(mComicManager.getSource()); + mManga = Kami.getMangaById(source); + mComic = mComicManager.getComic(id, source, cid); } @Override public void onCreate() { super.onCreate(); - mManga.into(mComicManager.getComic()); + mManga.into(mComic); } @Override public void onDestroy() { super.onDestroy(); mManga.cancel(); + if (mComic.getId() != null) { + mComicManager.updateComic(mComic); + } + } + + public Comic getComic() { + return mComic; } - public void saveComic() { - mComicManager.saveComic(); + public boolean isComicFavorite() { + return mComic.getFavorite() != null; } - public void onItemClick(int position) { - if (position != 0) { - Intent intent = StreamReaderActivity.createIntent(mDetailActivity, position - 1); - mDetailActivity.startActivity(intent); + public void favoriteComic() { + mComic.setFavorite(System.currentTimeMillis()); + if (mComic.getId() == null) { + long id = mComicManager.insertComic(mComic); + mComic.setId(id); } + EventBus.getDefault().post(new EventMessage(EventMessage.FAVORITE_COMIC, new MiniComic(mComic))); } - public void onStarClick() { - if (mComicManager.isComicStar()) { - mComicManager.unfavoriteComic(); - mDetailActivity.setStarButtonRes(R.drawable.ic_favorite_border_white_24dp); - mDetailActivity.showSnackbar("取消收藏成功"); - } else { - mComicManager.favoriteComic(); - mDetailActivity.setStarButtonRes(R.drawable.ic_favorite_white_24dp); - mDetailActivity.showSnackbar("收藏成功"); + public void unfavoriteComic() { + long id = mComic.getId(); + mComic.setFavorite(null); + if (mComic.getHistory() == null) { + mComicManager.deleteComic(id); + mComic.setId(null); } + EventBus.getDefault().post(new EventMessage(EventMessage.UN_FAVORITE_COMIC, id)); } + @SuppressWarnings("unchecked") @Subscribe(threadMode = ThreadMode.MAIN) public void onEvent(EventMessage msg) { switch (msg.getType()) { case EventMessage.LOAD_COMIC_SUCCESS: - initView((List) msg.getData()); + mDetailActivity.setView(mComic, (List) msg.getData()); break; case EventMessage.LOAD_COMIC_FAIL: - initView(new LinkedList()); - break; - case EventMessage.AFTER_READ: - mDetailActivity.setLastChapter((String) msg.getData()); + mDetailActivity.setView(mComic, new LinkedList()); break; case EventMessage.NETWORK_ERROR: - mDetailActivity.hideProgressBar(); - mDetailActivity.showSnackbar("网络错误"); + mDetailActivity.setView(mComic, null); + break; + case EventMessage.COMIC_LAST_CHANGE: + String last = (String) msg.getData(); + mComic.setHistory(System.currentTimeMillis()); + mComic.setLast(last); + mComic.setPage(1); + if (mComic.getId() == null) { + long id = mComicManager.insertComic(mComic); + mComic.setId(id); + } + EventBus.getDefault().post(new EventMessage(EventMessage.HISTORY_COMIC, new MiniComic(mComic))); + mDetailActivity.setLastChapter(last); + break; + case EventMessage.COMIC_PAGE_CHANGE: + mComic.setPage((Integer) msg.getData()); break; - } - } - - private void initView(List list) { - mComicManager.setChapters(list); - String last = mComicManager.getLast(); - mDetailActivity.initRecyclerView(mComicManager.getComic(), list, last); - int resId = mComicManager.isComicStar() ? R.drawable.ic_favorite_white_24dp : R.drawable.ic_favorite_border_white_24dp; - mDetailActivity.setStarButtonRes(resId); - mDetailActivity.setStarButtonVisible(); - mDetailActivity.hideProgressBar(); - if (list.isEmpty()) { - mDetailActivity.showSnackbar("解析错误或此漫画已被屏蔽"); } } diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/MainPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/MainPresenter.java index 2516e2f7..bef94e18 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/MainPresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/MainPresenter.java @@ -5,14 +5,13 @@ import android.view.MenuItem; import com.hiroshi.cimoc.R; +import com.hiroshi.cimoc.model.EventMessage; import com.hiroshi.cimoc.ui.activity.MainActivity; import com.hiroshi.cimoc.ui.fragment.AboutFragment; import com.hiroshi.cimoc.ui.fragment.CimocFragment; import com.hiroshi.cimoc.ui.fragment.FavoriteFragment; import com.hiroshi.cimoc.ui.fragment.HistoryFragment; -import com.hiroshi.cimoc.model.EventMessage; import com.hiroshi.cimoc.ui.fragment.SettingsFragment; -import com.hiroshi.cimoc.utils.PreferenceMaster; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; @@ -23,7 +22,6 @@ public class MainPresenter extends BasePresenter { private MainActivity mMainActivity; - private long mExitTime; private int mCheckedItem; private FragmentManager mFragmentManager; @@ -37,7 +35,6 @@ public class MainPresenter extends BasePresenter { public MainPresenter(MainActivity activity, int item) { mMainActivity = activity; mCheckedItem = item; - mExitTime = 0; initFragment(); } @@ -69,7 +66,6 @@ public void onCreate() { .show(mCurrentFragment) .commit(); mMainActivity.setCheckedItem(mCheckedItem); - mMainActivity.setTitle(PreferenceMaster.getTitleById(mCheckedItem)); } private void initFragment() { @@ -81,17 +77,6 @@ private void initFragment() { mAboutFragment = new AboutFragment(); } - public void onBackPressed() { - if (mMainActivity.isDrawerOpen()) { - mMainActivity.closeDrawer(); - } else if (System.currentTimeMillis() - mExitTime > 2000) { - mMainActivity.showSnackbar("再按一次退出程序"); - mExitTime = System.currentTimeMillis(); - } else { - mMainActivity.finish(); - } - } - public void transFragment() { switch (mCheckedItem) { default: diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/ReaderPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/ReaderPresenter.java index faf1d949..7a7b6408 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/ReaderPresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/ReaderPresenter.java @@ -1,14 +1,13 @@ package com.hiroshi.cimoc.presenter; -import com.hiroshi.cimoc.core.ComicManager; import com.hiroshi.cimoc.core.Kami; import com.hiroshi.cimoc.core.base.Manga; import com.hiroshi.cimoc.model.Chapter; import com.hiroshi.cimoc.model.EventMessage; -import com.hiroshi.cimoc.ui.activity.ReaderActivity; -import com.hiroshi.cimoc.ui.adapter.PicturePagerAdapter; +import com.hiroshi.cimoc.ui.activity.PageReaderActivity; import com.hiroshi.cimoc.ui.adapter.PreloadAdapter; +import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; @@ -21,27 +20,29 @@ public class ReaderPresenter extends BasePresenter { private final static int LOAD_PREV = 1; private final static int LOAD_NEXT = 2; - private ReaderActivity mReaderActivity; + private PageReaderActivity mPageReaderActivity; private PreloadAdapter mPreloadAdapter; - private ComicManager mComicManager; private Manga mManga; + private String cid; + private String last; + private Integer page; private int status; - private boolean load; - public ReaderPresenter(ReaderActivity activity, int position) { - mReaderActivity = activity; - mComicManager = ComicManager.getInstance(); - mPreloadAdapter = new PreloadAdapter(mComicManager.getChapters(), position); - mManga = Kami.getMangaById(mComicManager.getSource()); + public ReaderPresenter(PageReaderActivity activity, int source, String cid, String last, Integer page, Chapter[] array, int position) { + mPageReaderActivity = activity; + mPreloadAdapter = new PreloadAdapter(array, position); + mManga = Kami.getMangaById(source); + this.cid = cid; + this.last = last; + this.page = page; } @Override public void onCreate() { super.onCreate(); - load = false; status = LOAD_NEXT; - mManga.browse(mComicManager.getCid(), mPreloadAdapter.getNextChapter().getPath()); + mManga.browse(cid, mPreloadAdapter.getNextChapter().getPath()); } @Override @@ -50,58 +51,52 @@ public void onDestroy() { mManga.cancel(); } - public void afterRead(int progress) { - if (load) { - mComicManager.afterRead(progress); + public void setPage(int progress) { + if (mPreloadAdapter.isLoad()) { + EventBus.getDefault().post(new EventMessage(EventMessage.COMIC_PAGE_CHANGE, progress)); } } - public void onPageStateIdle(boolean isFirst) { + public void loadNext() { if (status == LOAD_NULL) { - Chapter chapter = isFirst ? mPreloadAdapter.getPrevChapter() : mPreloadAdapter.getNextChapter(); + Chapter chapter = mPreloadAdapter.getNextChapter(); if (chapter != null) { - status = isFirst ? LOAD_PREV : LOAD_NEXT; - mManga.browse(mComicManager.getCid(), chapter.getPath()); + status = LOAD_NEXT; + mManga.browse(cid, chapter.getPath()); + mPageReaderActivity.showToast("正在加载下一话"); } else { - mReaderActivity.notifySpecialPage(isFirst, PicturePagerAdapter.STATUS_NULL); + mPageReaderActivity.showToast("后面没有了"); + } + } + } + + public void loadPrev() { + if (status == LOAD_NULL) { + Chapter chapter = mPreloadAdapter.getPrevChapter(); + if (chapter != null) { + status = LOAD_PREV; + mManga.browse(cid, chapter.getPath()); + mPageReaderActivity.showToast("正在加载上一话"); + } else { + mPageReaderActivity.showToast("前面没有了"); } } } public void onChapterToNext() { Chapter chapter = mPreloadAdapter.nextChapter(); - if (chapter == null) { - mReaderActivity.hideChapterInfo(); - } else { - switchChapter(1, chapter.getCount(), chapter.getTitle(), chapter.getPath()); - } + switchChapter(1, chapter.getCount(), chapter.getTitle(), chapter.getPath()); } public void onChapterToPrev() { Chapter chapter = mPreloadAdapter.prevChapter(); - if (chapter == null) { - mReaderActivity.hideChapterInfo(); - } else { - switchChapter(chapter.getCount(), chapter.getCount(), chapter.getTitle(), chapter.getPath()); - } + switchChapter(chapter.getCount(), chapter.getCount(), chapter.getTitle(), chapter.getPath()); } - public void onProgressChanged(int value, boolean fromUser) { - if (fromUser) { - mReaderActivity.setCurrentItem(mPreloadAdapter.getOffset() + value); - } - } - - public int getSource() { - return mComicManager.getSource(); - } - - private void switchChapter(int progress, int max, String title, String path) { - mReaderActivity.updateChapterInfo(max, title); - if (progress != -1) { - mReaderActivity.setReadProgress(progress); - } - mComicManager.setLast(path); + private void switchChapter(int progress, int count, String title, String path) { + mPageReaderActivity.updateChapterInfo(count, title); + mPageReaderActivity.setReadProgress(progress); + EventBus.getDefault().post(new EventMessage(EventMessage.COMIC_LAST_CHANGE, path)); } @Subscribe(threadMode = ThreadMode.MAIN) @@ -110,30 +105,31 @@ public void onEvent(EventMessage msg) { case EventMessage.PARSE_PIC_SUCCESS: String[] array = (String[]) msg.getData(); Chapter chapter; - if (status == LOAD_PREV) { - mReaderActivity.setPrevImage(array); - chapter = mPreloadAdapter.movePrev(); - } else { - mReaderActivity.setNextImage(array); + if (!mPreloadAdapter.isLoad()) { + mPageReaderActivity.setNextImage(array); chapter = mPreloadAdapter.moveNext(); - } - chapter.setCount(array.length); - int page = mComicManager.getPage(); - if (!load && chapter.getPath().equals(mComicManager.getLast()) && page != -1) { - switchChapter(-1, array.length, chapter.getTitle(), chapter.getPath()); - mReaderActivity.setCurrentItem(page); - } else if (status == LOAD_PREV) { - switchChapter(array.length, array.length, chapter.getTitle(), chapter.getPath()); + if (!chapter.getPath().equals(last) || page == null) { + page = 1; + } + mPageReaderActivity.initLoad(page, array.length, chapter.getTitle()); + EventBus.getDefault().post(new EventMessage(EventMessage.COMIC_LAST_CHANGE, chapter.getPath())); } else { - switchChapter(1, array.length, chapter.getTitle(), chapter.getPath()); + if (status == LOAD_PREV) { + mPageReaderActivity.setPrevImage(array); + chapter = mPreloadAdapter.movePrev(); + } else { + mPageReaderActivity.setNextImage(array); + chapter = mPreloadAdapter.moveNext(); + } + mPageReaderActivity.loadSuccess(status == LOAD_NEXT); + mPageReaderActivity.showToast("加载成功"); } - load = true; - mReaderActivity.setNoneLimit(); + chapter.setCount(array.length); status = LOAD_NULL; break; case EventMessage.PARSE_PIC_FAIL: case EventMessage.NETWORK_ERROR: - mReaderActivity.notifySpecialPage(status == LOAD_PREV, PicturePagerAdapter.STATUS_ERROR); + mPageReaderActivity.showToast("加载错误"); break; } } diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/ResultPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/ResultPresenter.java index aafaac57..70a0a277 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/ResultPresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/ResultPresenter.java @@ -1,17 +1,15 @@ package com.hiroshi.cimoc.presenter; -import android.content.Intent; - import com.hiroshi.cimoc.core.Kami; import com.hiroshi.cimoc.core.base.Manga; import com.hiroshi.cimoc.model.Comic; -import com.hiroshi.cimoc.ui.activity.DetailActivity; -import com.hiroshi.cimoc.ui.activity.ResultActivity; import com.hiroshi.cimoc.model.EventMessage; +import com.hiroshi.cimoc.ui.activity.ResultActivity; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; +import java.util.LinkedList; import java.util.List; /** @@ -53,28 +51,19 @@ public void onScrolled(int dy, int last, int count) { } } - public void onItemClick(Comic comic) { - Intent intent = DetailActivity.createIntent(mResultActivity, comic.getId(), comic.getSource(), comic.getCid()); - mResultActivity.startActivity(intent); - } - + @SuppressWarnings("unchecked") @Subscribe(threadMode = ThreadMode.MAIN) public void onEvent(EventMessage msg) { switch (msg.getType()) { case EventMessage.SEARCH_SUCCESS: - mResultActivity.hideProgressBar(); - mResultActivity.addAll((List) msg.getData()); + mResultActivity.addResultSet((List) msg.getData()); isLoading = false; break; case EventMessage.SEARCH_FAIL: - if (page == 1) { - mResultActivity.hideProgressBar(); - mResultActivity.showSnackbar("搜索结果为空"); - } + mResultActivity.addResultSet(new LinkedList()); break; case EventMessage.NETWORK_ERROR: - mResultActivity.hideProgressBar(); - mResultActivity.showSnackbar("网络错误"); + mResultActivity.addResultSet(null); isLoading = false; break; } diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/StreamReaderPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/StreamReaderPresenter.java index 775c1f49..8f65e299 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/StreamReaderPresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/StreamReaderPresenter.java @@ -1,6 +1,7 @@ package com.hiroshi.cimoc.presenter; -import com.hiroshi.cimoc.core.ComicManager; +import android.util.Log; + import com.hiroshi.cimoc.core.Kami; import com.hiroshi.cimoc.core.base.Manga; import com.hiroshi.cimoc.model.Chapter; @@ -8,6 +9,7 @@ import com.hiroshi.cimoc.ui.activity.StreamReaderActivity; import com.hiroshi.cimoc.ui.adapter.PreloadAdapter; +import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; @@ -22,23 +24,27 @@ public class StreamReaderPresenter extends BasePresenter { private StreamReaderActivity mStreamReaderActivity; private PreloadAdapter mPreloadAdapter; - private ComicManager mComicManager; private Manga mManga; + private String cid; + private String last; + private Integer page; private int status; - public StreamReaderPresenter(StreamReaderActivity activity, int position) { + public StreamReaderPresenter(StreamReaderActivity activity, int source, String cid, String last, Integer page, Chapter[] array, int position) { mStreamReaderActivity = activity; - mComicManager = ComicManager.getInstance(); - mPreloadAdapter = new PreloadAdapter(mComicManager.getChapters(), position); - mManga = Kami.getMangaById(mComicManager.getSource()); + mPreloadAdapter = new PreloadAdapter(array, position); + mManga = Kami.getMangaById(source); + this.cid = cid; + this.last = last; + this.page = page; } @Override public void onCreate() { super.onCreate(); status = LOAD_NEXT; - mManga.browse(mComicManager.getCid(), mPreloadAdapter.getNextChapter().getPath()); + mManga.browse(cid, mPreloadAdapter.getNextChapter().getPath()); } @Override @@ -47,24 +53,35 @@ public void onDestroy() { mManga.cancel(); } + public void loadNext() { + if (status == LOAD_NULL) { + Chapter chapter = mPreloadAdapter.getNextChapter(); + if (chapter != null) { + status = LOAD_NEXT; + mManga.browse(cid, chapter.getPath()); + } + } + } + public void onScrolled(int dy, int last, int count) { if (last >= count - 1 && dy > 0 && status == LOAD_NULL) { Chapter chapter = mPreloadAdapter.getNextChapter(); if (chapter != null) { status = LOAD_NEXT; - mManga.browse(mComicManager.getCid(), chapter.getPath()); + mManga.browse(cid, chapter.getPath()); } - } else if (last <= 1 && dy < 0 && status == LOAD_NULL) { + } + /*else if (last <= 1 && dy < 0 && status == LOAD_NULL) { Chapter chapter = mPreloadAdapter.getPrevChapter(); if (chapter != null) { status = LOAD_PREV; - mManga.browse(mComicManager.getCid(), chapter.getPath()); + mManga.browse(cid, chapter.getPath()); } - } + }*/ } - public void afterRead(int progress) { - mComicManager.afterRead(progress); + public void setPage(int progress) { + EventBus.getDefault().post(new EventMessage(EventMessage.COMIC_PAGE_CHANGE, progress)); } public void onChapterToNext() { @@ -84,16 +101,12 @@ public void onChapterToPrev() { public void onProgressChanged(int value, boolean fromUser) { } - public int getSource() { - return mComicManager.getSource(); - } - private void switchChapter(int progress, int max, String title, String path) { mStreamReaderActivity.updateChapterInfo(max, title); if (progress != -1) { mStreamReaderActivity.setReadProgress(progress); } - mComicManager.setLast(path); + EventBus.getDefault().post(new EventMessage(EventMessage.COMIC_LAST_CHANGE, path)); } @Subscribe(threadMode = ThreadMode.MAIN) diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/BaseActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/BaseActivity.java index 1f7c3eff..a49b4e88 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/BaseActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/BaseActivity.java @@ -1,9 +1,11 @@ package com.hiroshi.cimoc.ui.activity; import android.os.Bundle; -import android.support.annotation.LayoutRes; +import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; +import android.view.View; +import android.widget.Toast; import com.hiroshi.cimoc.R; import com.hiroshi.cimoc.presenter.BasePresenter; @@ -20,7 +22,7 @@ public abstract class BaseActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(getLayoutView()); + setContentView(getLayoutRes()); ButterKnife.bind(this); initToolbar(); initPresenter(); @@ -47,14 +49,33 @@ protected void initToolbar() { } } - protected abstract @LayoutRes int getLayoutView(); + protected View getLayoutView() { + return null; + } + + protected String getDefaultTitle() { + return null; + } + + protected BasePresenter getPresenter() { + return null; + } - protected abstract String getDefaultTitle(); + protected void initPresenter() {} - protected abstract BasePresenter getPresenter(); + protected void initView() {} - protected abstract void initPresenter(); + protected abstract int getLayoutRes(); - protected abstract void initView(); + public void showSnackbar(String msg) { + View layout = getLayoutView(); + if (layout != null && layout.isShown()) { + Snackbar.make(layout, msg, Snackbar.LENGTH_SHORT).show(); + } + } + + public void showToast(String msg) { + Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); + } } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/DetailActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/DetailActivity.java index 1f653304..3fd82465 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/DetailActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/DetailActivity.java @@ -4,14 +4,12 @@ import android.content.Intent; import android.support.design.widget.CoordinatorLayout; import android.support.design.widget.FloatingActionButton; -import android.support.design.widget.Snackbar; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; import android.widget.ProgressBar; import com.hiroshi.cimoc.R; -import com.hiroshi.cimoc.core.ComicManager; import com.hiroshi.cimoc.model.Chapter; import com.hiroshi.cimoc.model.Comic; import com.hiroshi.cimoc.presenter.BasePresenter; @@ -37,10 +35,16 @@ public class DetailActivity extends BaseActivity { private ChapterAdapter mChapterAdapter; private DetailPresenter mPresenter; - @Override - public void onBackPressed() { - mPresenter.saveComic(); - super.onBackPressed(); + @OnClick(R.id.detail_star_btn) void onClick() { + if (mPresenter.isComicFavorite()) { + mPresenter.unfavoriteComic(); + mStarButton.setImageResource(R.drawable.ic_favorite_border_white_24dp); + showSnackbar("取消收藏成功"); + } else { + mPresenter.favoriteComic(); + mStarButton.setImageResource(R.drawable.ic_favorite_white_24dp); + showSnackbar("收藏成功"); + } } @Override @@ -54,16 +58,20 @@ public void onClick(View v) { }); } - @Override - protected void initView() {} - @Override protected void initPresenter() { - mPresenter = new DetailPresenter(this); + long id = getIntent().getLongExtra(EXTRA_ID, -1); + int source = getIntent().getIntExtra(EXTRA_SOURCE, -1); + String cid = getIntent().getStringExtra(EXTRA_CID); + if (id == -1) { + mPresenter = new DetailPresenter(this, null, source, cid); + } else { + mPresenter = new DetailPresenter(this, id, source, cid); + } } @Override - protected int getLayoutView() { + protected int getLayoutRes() { return R.layout.activity_detail; } @@ -77,51 +85,63 @@ protected BasePresenter getPresenter() { return mPresenter; } - @OnClick(R.id.detail_star_btn) void onClick() { - mPresenter.onStarClick(); - } - - public void setStarButtonRes(int resId) { - mStarButton.setImageResource(resId); - } - - public void setStarButtonVisible() { - mStarButton.setVisibility(View.VISIBLE); - } - - public void hideProgressBar() { - mProgressBar.setVisibility(View.GONE); - mCoordinatorLayout.setVisibility(View.VISIBLE); - } - - public void showSnackbar(String msg) { - if (mCoordinatorLayout.isShown()) { - Snackbar.make(mCoordinatorLayout, msg, Snackbar.LENGTH_SHORT).show(); - } + @Override + protected View getLayoutView() { + return mCoordinatorLayout; } public void setLastChapter(String last) { mChapterAdapter.setLast(last); } - public void initRecyclerView(Comic comic, List list, String last) { - mChapterAdapter = new ChapterAdapter(this, list, comic.getCover(), comic.getTitle(), + public void setView(Comic comic, List list) { + if (list == null) { + mProgressBar.setVisibility(View.GONE); + showSnackbar("网络错误"); + return; + } + + mChapterAdapter = new ChapterAdapter(this, list, comic.getSource(), comic.getCover(), comic.getTitle(), comic.getAuthor(), comic.getIntro(), comic.getStatus(), comic.getUpdate()); - mChapterAdapter.setLast(last); + mChapterAdapter.setLast(comic.getLast()); mChapterAdapter.setOnItemClickListener(new BaseAdapter.OnItemClickListener() { @Override public void onItemClick(View view, int position) { - mPresenter.onItemClick(position); + if (position != 0) { + Intent intent = PageReaderActivity.createIntent(DetailActivity.this, mPresenter.getComic(), + mChapterAdapter.getDateSet(), position - 1); + startActivity(intent); + } } }); + mRecyclerView.setItemAnimator(null); mRecyclerView.setLayoutManager(new GridLayoutManager(this, 4)); mRecyclerView.setAdapter(mChapterAdapter); mRecyclerView.addItemDecoration(mChapterAdapter.getItemDecoration()); + + if (comic.getFavorite() != null) { + mStarButton.setImageResource(R.drawable.ic_favorite_white_24dp); + } else { + mStarButton.setImageResource(R.drawable.ic_favorite_border_white_24dp); + } + mProgressBar.setVisibility(View.GONE); + mStarButton.setVisibility(View.VISIBLE); + mCoordinatorLayout.setVisibility(View.VISIBLE); + if (list.isEmpty()) { + showSnackbar("解析错误或此漫画已被屏蔽"); + } } + public static final String EXTRA_ID = "a"; + public static final String EXTRA_SOURCE = "b"; + public static final String EXTRA_CID = "c"; + public static Intent createIntent(Context context, Long id, int source, String cid) { - ComicManager.getInstance().setComic(id, source, cid); - return new Intent(context, DetailActivity.class); + Intent intent = new Intent(context, DetailActivity.class); + intent.putExtra(EXTRA_ID, id); + intent.putExtra(EXTRA_SOURCE, source); + intent.putExtra(EXTRA_CID, cid); + return intent; } } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/MainActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/MainActivity.java index 8306c2d8..fab9e9c8 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/MainActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/MainActivity.java @@ -1,7 +1,6 @@ package com.hiroshi.cimoc.ui.activity; import android.support.design.widget.NavigationView; -import android.support.design.widget.Snackbar; import android.support.v4.view.GravityCompat; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBarDrawerToggle; @@ -29,15 +28,23 @@ public class MainActivity extends BaseActivity { @BindView(R.id.main_progress_bar) ProgressBar mProgressBar; private MainPresenter mPresenter; + private long mExitTime; @Override - protected void initPresenter() { - int item = CimocApplication.getPreferences().getInt(PreferenceMaster.PREF_HOME, R.id.drawer_cimoc); - mPresenter = new MainPresenter(this, item); + public void onBackPressed() { + if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) { + mDrawerLayout.closeDrawer(GravityCompat.START); + } else if (System.currentTimeMillis() - mExitTime > 2000) { + showSnackbar("再按一次退出程序"); + mExitTime = System.currentTimeMillis(); + } else { + finish(); + } } @Override protected void initView() { + mExitTime = 0; ActionBarDrawerToggle drawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, mToolbar, 0, 0) { @Override @@ -61,27 +68,30 @@ public boolean onNavigationItemSelected(MenuItem item) { } @Override - protected int getLayoutView() { - return R.layout.activity_main; + protected void initPresenter() { + int home = CimocApplication.getPreferences().getInt(PreferenceMaster.PREF_HOME, PreferenceMaster.HOME_CIMOC); + mPresenter = new MainPresenter(this, PreferenceMaster.getHomeId(home)); } @Override - protected String getDefaultTitle() { - return null; + protected int getLayoutRes() { + return R.layout.activity_main; } @Override - protected BasePresenter getPresenter() { - return mPresenter; + protected View getLayoutView() { + return mDrawerLayout; } @Override - public void onBackPressed() { - mPresenter.onBackPressed(); + protected String getDefaultTitle() { + int home = CimocApplication.getPreferences().getInt(PreferenceMaster.PREF_HOME, PreferenceMaster.HOME_CIMOC); + return getResources().getStringArray(R.array.home_items)[home]; } - public boolean isDrawerOpen() { - return mDrawerLayout.isDrawerOpen(GravityCompat.START); + @Override + protected BasePresenter getPresenter() { + return mPresenter; } public void closeDrawer() { @@ -106,8 +116,4 @@ public void hideProgressBar() { mProgressBar.setVisibility(View.GONE); } - public void showSnackbar(String msg) { - Snackbar.make(mDrawerLayout, msg, Snackbar.LENGTH_SHORT).show(); - } - } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/PageReaderActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/PageReaderActivity.java new file mode 100644 index 00000000..e68bfeae --- /dev/null +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/PageReaderActivity.java @@ -0,0 +1,223 @@ +package com.hiroshi.cimoc.ui.activity; + +import android.content.Context; +import android.content.Intent; +import android.graphics.Point; +import android.support.v4.view.ViewPager; +import android.view.KeyEvent; +import android.view.View; + +import com.hiroshi.cimoc.CimocApplication; +import com.hiroshi.cimoc.R; +import com.hiroshi.cimoc.model.Chapter; +import com.hiroshi.cimoc.model.Comic; +import com.hiroshi.cimoc.presenter.BasePresenter; +import com.hiroshi.cimoc.presenter.ReaderPresenter; +import com.hiroshi.cimoc.ui.adapter.PicturePageAdapter; +import com.hiroshi.cimoc.ui.custom.LimitedViewPager; +import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeViewController; +import com.hiroshi.cimoc.utils.ControllerBuilderFactory; +import com.hiroshi.cimoc.utils.PreferenceMaster; + +import org.adw.library.widgets.discreteseekbar.DiscreteSeekBar; + +import java.util.LinkedList; +import java.util.List; + +import butterknife.BindView; + +/** + * Created by Hiroshi on 2016/7/7. + */ +public class PageReaderActivity extends ReaderActivity { + + @BindView(R.id.reader_view_pager) LimitedViewPager mViewPager; + + private PicturePageAdapter mPageAdapter; + private ReaderPresenter mPresenter; + + private boolean volume; + + @Override + protected void onPause() { + super.onPause(); + mPresenter.setPage(progress); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (volume) { + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + mViewPager.prevPage(); + return true; + case KeyEvent.KEYCODE_VOLUME_DOWN: + mViewPager.nextPage(); + return true; + } + } + return super.onKeyDown(keyCode, event); + } + + @Override + protected void initView() { + volume = CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_VOLUME, false); + progress = max = 1; + + mPageAdapter = new PicturePageAdapter(new LinkedList(), getLayoutInflater(), + new PhotoDraweeViewController.OnSingleTapListener() { + @Override + public void onSingleTap(View view, float x, float y) { + Point point = new Point(); + getWindowManager().getDefaultDisplay().getSize(point); + float limitX = point.x / 3.0f; + float limitY = point.y / 3.0f; + if (x < limitX) { + mViewPager.prevPage(); + } else if (x > 2 * limitX) { + mViewPager.nextPage(); + } else if (y >= 2 * limitY) { + if (mToolLayout.isShown()) { + mToolLayout.setVisibility(View.VISIBLE); + } else { + mSeekBar.setProgress(progress); + mSeekBar.setMax(max); + mToolLayout.setVisibility(View.VISIBLE); + } + } + } + }, ControllerBuilderFactory.getControllerBuilder(getIntent().getIntExtra(EXTRA_SOURCE, -1), this)); + + mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {} + + @Override + public void onPageSelected(int position) { + int current = mPageAdapter.getCurrent(); + if (position == current) { + return; + } + mPageAdapter.setCurrent(position); + if (mPageAdapter.isToLeft()) { + mViewPager.setLimit(LimitedViewPager.LIMIT_RIGHT); + } else if (mPageAdapter.isToRight()) { + mViewPager.setLimit(LimitedViewPager.LIMIT_LEFT); + } else { + mViewPager.setLimit(LimitedViewPager.LIMIT_NONE); + } + if (position > current && progress == max) { + mPresenter.onChapterToNext(); + } else if (position < current && progress == 1) { + mPresenter.onChapterToPrev(); + } else { + setReadProgress(progress + position - current); + } + } + + @Override + public void onPageScrollStateChanged(int state) { + switch (state) { + case ViewPager.SCROLL_STATE_DRAGGING: + if (mToolLayout.isShown()) { + mToolLayout.setVisibility(View.INVISIBLE); + } + break; + case ViewPager.SCROLL_STATE_IDLE: + if (mViewPager.getLimit() == LimitedViewPager.LIMIT_RIGHT) { + mPresenter.loadPrev(); + } else if (mViewPager.getLimit() == LimitedViewPager.LIMIT_LEFT) { + mPresenter.loadNext(); + } + break; + } + } + }); + mViewPager.setAdapter(mPageAdapter); + mViewPager.setCurrentItem(PicturePageAdapter.MAX_COUNT / 2 + 1, false); + mViewPager.setOffscreenPageLimit(3); + + mSeekBar.setOnProgressChangeListener(new DiscreteSeekBar.OnProgressChangeListener() { + @Override + public void onProgressChanged(DiscreteSeekBar seekBar, int value, boolean fromUser) { + if (fromUser) { + mViewPager.setCurrentItem(mPageAdapter.getCurrent() + value - progress, false); + } + } + + @Override + public void onStartTrackingTouch(DiscreteSeekBar seekBar) {} + + @Override + public void onStopTrackingTouch(DiscreteSeekBar seekBar) {} + }); + } + + @Override + protected void initPresenter() { + int source = getIntent().getIntExtra(EXTRA_SOURCE, -1); + String cid = getIntent().getStringExtra(EXTRA_CID); + String last = getIntent().getStringExtra(EXTRA_LAST); + int page = getIntent().getIntExtra(EXTRA_PAGE, -1); + String[] title = getIntent().getStringArrayExtra(EXTRA_TITLE); + String[] path = getIntent().getStringArrayExtra(EXTRA_PATH); + Chapter[] array = fromArray(title, path); + int position = getIntent().getIntExtra(EXTRA_POSITION, 0); + mPresenter = new ReaderPresenter(this, source, cid, last, page, array, position); + } + + @Override + protected BasePresenter getPresenter() { + return mPresenter; + } + + @Override + protected int getLayoutRes() { + return R.layout.activity_reader; + } + + public void setPrevImage(String[] array) { + mPageAdapter.setPrevImages(array); + } + + public void setNextImage(String[] array) { + mPageAdapter.setNextImages(array); + } + + public void loadSuccess(boolean isNext) { + if (isNext && mViewPager.getLimit() == LimitedViewPager.LIMIT_LEFT || + !isNext && mViewPager.getLimit() == LimitedViewPager.LIMIT_RIGHT) { + mViewPager.setLimit(LimitedViewPager.LIMIT_NONE); + } + } + + public void initLoad(int progress, int max, String title) { + this.max = max; + mChapterTitle.setText(title); + if (progress != 1) { + mViewPager.setCurrentItem(PicturePageAdapter.MAX_COUNT / 2 + progress); + } else { + mViewPager.setLimit(LimitedViewPager.LIMIT_RIGHT); + String text = progress + "/" + max; + mChapterPage.setText(text); + } + } + + public void updateChapterInfo(int count, String title) { + max = count; + mChapterTitle.setText(title); + } + + public void setReadProgress(int progress) { + this.progress = progress; + String text = progress + "/" + max; + mChapterPage.setText(text); + } + + public static Intent createIntent(Context context, Comic comic, List list, int position) { + Intent intent = new Intent(context, PageReaderActivity.class); + putExtras(intent, comic, list, position); + return intent; + } + +} diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java index bcf3d7f7..f1c43a1b 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java @@ -1,184 +1,72 @@ package com.hiroshi.cimoc.ui.activity; -import android.content.Context; import android.content.Intent; -import android.graphics.Point; -import android.support.v4.view.ViewPager; -import android.view.View; import android.widget.LinearLayout; import android.widget.TextView; import com.hiroshi.cimoc.R; -import com.hiroshi.cimoc.presenter.BasePresenter; -import com.hiroshi.cimoc.presenter.ReaderPresenter; -import com.hiroshi.cimoc.ui.adapter.PicturePagerAdapter; -import com.hiroshi.cimoc.ui.custom.LimitedViewPager; -import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeViewController; -import com.hiroshi.cimoc.utils.ControllerBuilderFactory; +import com.hiroshi.cimoc.model.Chapter; +import com.hiroshi.cimoc.model.Comic; import org.adw.library.widgets.discreteseekbar.DiscreteSeekBar; -import java.util.LinkedList; +import java.util.List; import butterknife.BindView; /** - * Created by Hiroshi on 2016/7/7. + * Created by Hiroshi on 2016/8/6. */ -public class ReaderActivity extends BaseActivity { +public abstract class ReaderActivity extends BaseActivity { - public static final String EXTRA_POSITION = "extra_position"; - - @BindView(R.id.reader_view_pager) LimitedViewPager mViewPager; @BindView(R.id.reader_chapter_title) TextView mChapterTitle; @BindView(R.id.reader_chapter_page) TextView mChapterPage; @BindView(R.id.reader_tool_bar) LinearLayout mToolLayout; @BindView(R.id.reader_seek_bar) DiscreteSeekBar mSeekBar; - private PicturePagerAdapter mPagerAdapter; - private ReaderPresenter mPresenter; - - private int progress; - - @Override - public void onBackPressed() { - mPresenter.afterRead(mSeekBar.getProgress()); - super.onBackPressed(); - } - - @Override - protected void initView() { - progress = 0; - - mPagerAdapter = new PicturePagerAdapter(new LinkedList(), getLayoutInflater(), - new PhotoDraweeViewController.OnSingleTapListener() { - @Override - public void onSingleTap(View view, float x, float y) { - Point point = new Point(); - getWindowManager().getDefaultDisplay().getSize(point); - float limitX = point.x / 3.0f; - float limitY = point.y / 3.0f; - if (limitX <= x && x <= 2 * limitX && limitY <= y && y <= 2 * limitY) { - int visibility = mToolLayout.isShown() ? View.GONE : View.VISIBLE; - mToolLayout.setVisibility(visibility); - } - } - }, ControllerBuilderFactory.getControllerBuilder(mPresenter.getSource(), this)); - - mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { - @Override - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {} - - @Override - public void onPageSelected(int position) { - int current = mPagerAdapter.getCurrent(); - if (position == current) { - return; - } - mPagerAdapter.setCurrent(position); - mViewPager.setLimit(mPagerAdapter.getLimit()); - if (position > current && progress == mSeekBar.getMax()) { - mPresenter.onChapterToNext(); - } else if (position < current && progress == 1) { - mPresenter.onChapterToPrev(); - } else { - setReadProgress(progress + position - current); - } - } - - @Override - public void onPageScrollStateChanged(int state) { - if (state == ViewPager.SCROLL_STATE_IDLE && mViewPager.getLimit() == LimitedViewPager.LIMIT_RIGHT) { - mPresenter.onPageStateIdle(true); - } else if (state == ViewPager.SCROLL_STATE_IDLE && mViewPager.getLimit() == LimitedViewPager.LIMIT_LEFT) { - mPresenter.onPageStateIdle(false); - } - } - }); - mViewPager.setAdapter(mPagerAdapter); - mViewPager.setCurrentItem(PicturePagerAdapter.MAX_COUNT / 2 + 1, false); - mViewPager.setOffscreenPageLimit(3); - - mSeekBar.setOnProgressChangeListener(new DiscreteSeekBar.OnProgressChangeListener() { - @Override - public void onProgressChanged(DiscreteSeekBar seekBar, int value, boolean fromUser) { - mPresenter.onProgressChanged(value, fromUser); - } - - @Override - public void onStartTrackingTouch(DiscreteSeekBar seekBar) {} - - @Override - public void onStopTrackingTouch(DiscreteSeekBar seekBar) {} - }); - } + protected int progress; + protected int max; @Override protected void initToolbar() {} - @Override - protected void initPresenter() { - int position = getIntent().getIntExtra(EXTRA_POSITION, 0); - mPresenter = new ReaderPresenter(this, position); - } - - @Override - protected String getDefaultTitle() { - return null; - } - - @Override - protected BasePresenter getPresenter() { - return mPresenter; - } - - @Override - protected int getLayoutView() { - return R.layout.activity_reader; - } - - public void setPrevImage(String[] array) { - mPagerAdapter.setPrevImages(array); - } - - public void setNextImage(String[] array) { - mPagerAdapter.setNextImages(array); - } - - public void setNoneLimit() { - mViewPager.setLimit(LimitedViewPager.LIMIT_NONE); - } - - public void notifySpecialPage(boolean isFirst, int status) { - mPagerAdapter.notifySpecialPage(isFirst, status); - } - - public void hideChapterInfo() { - mToolLayout.setVisibility(View.GONE); - mChapterPage.setText(null); - mChapterTitle.setText(null); - } - - public void setCurrentItem(int offset) { - mViewPager.setCurrentItem(mPagerAdapter.getLeft() + offset, false); - } - - public void updateChapterInfo(int max, String title) { - mSeekBar.setMax(max); - mChapterTitle.setText(title); + protected static final String EXTRA_SOURCE = "a"; + protected static final String EXTRA_CID = "b"; + protected static final String EXTRA_LAST = "c"; + protected static final String EXTRA_PAGE = "d"; + protected static final String EXTRA_TITLE = "e"; + protected static final String EXTRA_PATH = "f"; + protected static final String EXTRA_POSITION = "g"; + + protected static void putExtras(Intent intent, Comic comic, List list, int position) { + intent.putExtra(EXTRA_SOURCE, comic.getSource()); + intent.putExtra(EXTRA_CID, comic.getCid()); + intent.putExtra(EXTRA_LAST, comic.getLast()); + intent.putExtra(EXTRA_PAGE, comic.getPage()); + String[][] array = fromList(list); + intent.putExtra(EXTRA_TITLE, array[0]); + intent.putExtra(EXTRA_PATH, array[1]); + intent.putExtra(EXTRA_POSITION, position); } - public void setReadProgress(int value) { - mSeekBar.setProgress(value); - String pageString = value + "/" + mSeekBar.getMax(); - mChapterPage.setText(pageString); - progress = value; + protected static String[][] fromList(List list) { + int size = list.size(); + String[] title = new String[size]; + String[] path = new String[size]; + for (int i = 0; i != size; ++i) { + title[i] = list.get(i).getTitle(); + path[i] = list.get(i).getPath(); + } + return new String[][] { title, path }; } - public static Intent createIntent(Context context, int position) { - Intent intent = new Intent(context, ReaderActivity.class); - intent.putExtra(EXTRA_POSITION, position); - return intent; + protected static Chapter[] fromArray(String[] title, String[] path) { + int size = title.length; + Chapter[] array = new Chapter[size]; + for (int i = 0; i != size; ++i) { + array[i] = new Chapter(title[i], path[i]); + } + return array; } } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/ResultActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/ResultActivity.java index dcd7665a..c8969665 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/ResultActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/ResultActivity.java @@ -2,7 +2,6 @@ import android.content.Context; import android.content.Intent; -import android.support.design.widget.Snackbar; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; @@ -26,9 +25,6 @@ */ public class ResultActivity extends BaseActivity { - public static final String EXTRA_KEYWORD = "extra_keyword"; - public static final String EXTRA_SOURCE = "extra_source"; - @BindView(R.id.result_comic_list) RecyclerView mRecyclerView; @BindView(R.id.result_progress_bar) ProgressBar mProgressBar; @BindView(R.id.result_layout) LinearLayout mLinearLayout; @@ -71,16 +67,23 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { mResultAdapter.setOnItemClickListener(new BaseAdapter.OnItemClickListener() { @Override public void onItemClick(View view, int position) { - mPresenter.onItemClick(mResultAdapter.getItem(position)); + Comic comic = mResultAdapter.getItem(position); + Intent intent = DetailActivity.createIntent(ResultActivity.this, comic.getId(), comic.getSource(), comic.getCid()); + startActivity(intent); } }); } @Override - protected int getLayoutView() { + protected int getLayoutRes() { return R.layout.activtiy_result; } + @Override + protected View getLayoutView() { + return mLinearLayout; + } + @Override protected String getDefaultTitle() { return "搜索结果"; @@ -91,22 +94,23 @@ protected BasePresenter getPresenter() { return mPresenter; } - public void hideProgressBar() { + public void addResultSet(List list) { + if (list == null) { + showSnackbar("网络错误"); + } else if (list.isEmpty() && mResultAdapter.getItemCount() == 0) { + showSnackbar("搜索结果为空"); + } else { + mResultAdapter.addAll(list); + } + if (mProgressBar.isShown()) { mProgressBar.setVisibility(View.GONE); mRecyclerView.setVisibility(View.VISIBLE); } } - public void showSnackbar(String msg) { - if (mLinearLayout.isShown()) { - Snackbar.make(mLinearLayout, msg, Snackbar.LENGTH_SHORT).show(); - } - } - - public void addAll(List list) { - mResultAdapter.addAll(list); - } + public static final String EXTRA_KEYWORD = "a"; + public static final String EXTRA_SOURCE = "b"; public static Intent createIntent(Context context, String keyword, int source) { Intent intent = new Intent(context, ResultActivity.class); diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/StreamReaderActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/StreamReaderActivity.java index 5e4bd5d6..1393dc72 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/StreamReaderActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/StreamReaderActivity.java @@ -4,52 +4,46 @@ import android.content.Intent; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; +import android.util.Log; import android.view.View; -import android.widget.LinearLayout; -import android.widget.TextView; import com.hiroshi.cimoc.R; +import com.hiroshi.cimoc.model.Chapter; +import com.hiroshi.cimoc.model.Comic; import com.hiroshi.cimoc.presenter.BasePresenter; import com.hiroshi.cimoc.presenter.StreamReaderPresenter; import com.hiroshi.cimoc.ui.adapter.PictureStreamAdapter; import com.hiroshi.cimoc.utils.ControllerBuilderFactory; -import org.adw.library.widgets.discreteseekbar.DiscreteSeekBar; - import java.util.Arrays; +import java.util.List; import butterknife.BindView; /** * Created by Hiroshi on 2016/8/5. */ -public class StreamReaderActivity extends BaseActivity { - - public static final String EXTRA_POSITION = "extra_position"; +public class StreamReaderActivity extends ReaderActivity{ @BindView(R.id.reader_recycler_view) RecyclerView mRecyclerView; - @BindView(R.id.reader_chapter_title) TextView mChapterTitle; - @BindView(R.id.reader_chapter_page) TextView mChapterPage; - @BindView(R.id.reader_tool_bar) LinearLayout mToolLayout; - @BindView(R.id.reader_seek_bar) DiscreteSeekBar mSeekBar; private PictureStreamAdapter mStreamAdapter; private StreamReaderPresenter mPresenter; private LinearLayoutManager mLayoutManager; - private int progress; + private int position; @Override - public void onBackPressed() { - mPresenter.afterRead(mSeekBar.getProgress()); - super.onBackPressed(); + protected void onPause() { + super.onPause(); + mPresenter.setPage(mSeekBar.getProgress()); } @Override protected void initView() { - progress = 0; + progress = 1; mLayoutManager = new LinearLayoutManager(this); - mStreamAdapter = new PictureStreamAdapter(this, ControllerBuilderFactory.getControllerBuilder(mPresenter.getSource(), this)); + mStreamAdapter = new PictureStreamAdapter(this, ControllerBuilderFactory.getControllerBuilder(getIntent().getIntExtra(EXTRA_SOURCE, -1), this)); mRecyclerView.setItemAnimator(null); mRecyclerView.setLayoutManager(mLayoutManager); mRecyclerView.setAdapter(mStreamAdapter); @@ -57,23 +51,36 @@ protected void initView() { mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { - mPresenter.onScrolled(dy, mLayoutManager.findLastVisibleItemPosition(), mStreamAdapter.getItemCount()); + int item = mLayoutManager.findFirstVisibleItemPosition(); + if (item != position) { + position = item; + if (dy > 0) { + ++progress; + if (progress == mSeekBar.getMax()) { + + } + } else { + --progress; + } + mPresenter.onScrolled(dy, position, mStreamAdapter.getItemCount()); + } + + Log.e("--------------", "-----" + position); } }); } - @Override - protected void initToolbar() {} - @Override protected void initPresenter() { + int source = getIntent().getIntExtra(EXTRA_SOURCE, -1); + String cid = getIntent().getStringExtra(EXTRA_CID); + String last = getIntent().getStringExtra(EXTRA_LAST); + int page = getIntent().getIntExtra(EXTRA_PAGE, -1); + String[] title = getIntent().getStringArrayExtra(EXTRA_TITLE); + String[] path = getIntent().getStringArrayExtra(EXTRA_PATH); + Chapter[] array = fromArray(title, path); int position = getIntent().getIntExtra(EXTRA_POSITION, 0); - mPresenter = new StreamReaderPresenter(this, position); - } - - @Override - protected String getDefaultTitle() { - return null; + mPresenter = new StreamReaderPresenter(this, source, cid, last, page, array, position); } @Override @@ -82,7 +89,7 @@ protected BasePresenter getPresenter() { } @Override - protected int getLayoutView() { + protected int getLayoutRes() { return R.layout.activity_stream_reader; } @@ -112,9 +119,9 @@ public void setReadProgress(int value) { progress = value; } - public static Intent createIntent(Context context, int position) { + public static Intent createIntent(Context context, Comic comic, List list, int position) { Intent intent = new Intent(context, StreamReaderActivity.class); - intent.putExtra(EXTRA_POSITION, position); + putExtras(intent, comic, list, position); return intent; } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/BaseAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/BaseAdapter.java index b70c8f1c..11c94118 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/BaseAdapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/BaseAdapter.java @@ -61,6 +61,10 @@ public void clear() { notifyDataSetChanged(); } + public List getDateSet() { + return mDataSet; + } + public void setData(List list) { mDataSet.clear(); mDataSet.addAll(list); diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ChapterAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ChapterAdapter.java index f340237c..6017a159 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ChapterAdapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ChapterAdapter.java @@ -8,9 +8,11 @@ import android.view.ViewGroup; import android.widget.TextView; +import com.facebook.drawee.backends.pipeline.PipelineDraweeControllerBuilder; import com.facebook.drawee.view.SimpleDraweeView; import com.hiroshi.cimoc.R; import com.hiroshi.cimoc.model.Chapter; +import com.hiroshi.cimoc.utils.ControllerBuilderFactory; import java.util.List; @@ -21,6 +23,7 @@ */ public class ChapterAdapter extends BaseAdapter { + private int source; private String title; private String image; private String update; @@ -51,8 +54,9 @@ public HeaderHolder(View view) { } } - public ChapterAdapter(Context context, List list, String image, String title, String author, String intro, boolean status, String update) { + public ChapterAdapter(Context context, List list, int source, String image, String title, String author, String intro, boolean status, String update) { super(context, list); + this.source = source; this.image = image; this.title = title; this.intro = intro; @@ -105,7 +109,8 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (position == 0) { HeaderHolder headerHolder = (HeaderHolder) holder; - headerHolder.mComicImage.setImageURI(image); + PipelineDraweeControllerBuilder builder = ControllerBuilderFactory.getControllerBuilder(source, mContext); + headerHolder.mComicImage.setController(builder.setUri(image).build()); headerHolder.mComicTitle.setText(title); headerHolder.mComicIntro.setText(intro); headerHolder.mComicStatus.setText(status ? "完结" : "连载中"); diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/FavoriteAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/FavoriteAdapter.java index ae658a7c..cf01c8fe 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/FavoriteAdapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/FavoriteAdapter.java @@ -51,6 +51,7 @@ public MiniComic cancelNew(int position) { int temp = findFirstNormal(); mDataSet.add(temp, comic); notifyItemMoved(position, temp); + notifyItemChanged(temp); } return comic; } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePagerAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePageAdapter.java similarity index 62% rename from app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePagerAdapter.java rename to app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePageAdapter.java index 163e7f53..5a55db2b 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePagerAdapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePageAdapter.java @@ -6,13 +6,11 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; -import android.widget.TextView; import com.facebook.drawee.backends.pipeline.PipelineDraweeControllerBuilder; import com.facebook.drawee.controller.BaseControllerListener; import com.facebook.imagepipeline.image.ImageInfo; import com.hiroshi.cimoc.R; -import com.hiroshi.cimoc.ui.custom.LimitedViewPager; import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeView; import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeViewController.OnSingleTapListener; @@ -22,27 +20,21 @@ /** * Created by Hiroshi on 2016/7/7. */ -public class PicturePagerAdapter extends PagerAdapter { +public class PicturePageAdapter extends PagerAdapter { public static final int MAX_COUNT = 20000; - public static final int STATUS_LOAD = 0; - public static final int STATUS_NULL = 1; - public static final int STATUS_ERROR = 2; - private List images; private LayoutInflater inflater; private OnSingleTapListener listener; private PipelineDraweeControllerBuilder builder; private int left; private int right; - private int pStatus; - private int nStatus; private int current; - public PicturePagerAdapter(List images, LayoutInflater inflater, OnSingleTapListener listener, - PipelineDraweeControllerBuilder builder) { + public PicturePageAdapter(List images, LayoutInflater inflater, OnSingleTapListener listener, + PipelineDraweeControllerBuilder builder) { this.images = images; this.inflater = inflater; this.listener = listener; @@ -50,8 +42,6 @@ public PicturePagerAdapter(List images, LayoutInflater inflater, OnSingl this.left = MAX_COUNT / 2; this.current = MAX_COUNT / 2 + 1; this.right = MAX_COUNT / 2 + 1; - this.pStatus = STATUS_LOAD; - this.nStatus = STATUS_LOAD; } public void setCurrent(int current) { @@ -62,10 +52,6 @@ public int getCurrent() { return current; } - public int getLeft() { - return left; - } - public void setPrevImages(String[] array) { images.addAll(0, Arrays.asList(array)); left -= array.length; @@ -78,24 +64,12 @@ public void setNextImages(String[] array) { notifyDataSetChanged(); } - public void notifySpecialPage(boolean isFirst, int status) { - if (isFirst) { - pStatus = status; - } else { - nStatus = status; - } - notifyDataSetChanged(); + public boolean isToLeft() { + return current == left + 1; } - public int getLimit() { - if (left + 1 == right) { - return LimitedViewPager.LIMIT_BOTH; - } else if (current == left) { - return LimitedViewPager.LIMIT_RIGHT; - } else if (current == right) { - return LimitedViewPager.LIMIT_LEFT; - } - return LimitedViewPager.LIMIT_NONE; + public boolean isToRight() { + return current == right - 1; } @Override @@ -121,28 +95,8 @@ public void destroyItem(ViewGroup container, int position, Object object) { @Override public Object instantiateItem(ViewGroup container, int position) { - View child; - if (position <= left || position >= right) { - child = inflater.inflate(R.layout.item_picture_msg, container, false); - TextView textView = (TextView) child.findViewById(R.id.picture_msg); - int what = STATUS_LOAD; - if (position == left) { - what = pStatus; - } else if (position == right) { - what = nStatus; - } - switch (what) { - case STATUS_LOAD: - textView.setText("等待加载中..."); - break; - case STATUS_NULL: - textView.setText("没有了 :("); - break; - case STATUS_ERROR: - textView.setText("加载错误 :("); - } - child.setTag(POSITION_NONE); - } else { + View child = inflater.inflate(R.layout.item_picture, container, false); + if (left < position && position < right) { child = inflater.inflate(R.layout.item_picture, container, false); final PhotoDraweeView draweeView = (PhotoDraweeView) child.findViewById(R.id.picture_image_view); draweeView.setScaleType(ImageView.ScaleType.FIT_CENTER); @@ -152,7 +106,7 @@ public Object instantiateItem(ViewGroup container, int position) { @Override public void onFinalImageSet(String id, ImageInfo imageInfo, Animatable animatable) { super.onFinalImageSet(id, imageInfo, animatable); - if (imageInfo == null || draweeView == null) { + if (imageInfo == null) { return; } draweeView.update(imageInfo.getWidth(), imageInfo.getHeight()); @@ -160,6 +114,8 @@ public void onFinalImageSet(String id, ImageInfo imageInfo, Animatable animatabl }).setTapToRetryEnabled(true); draweeView.setController(builder.setUri(images.get(position - left - 1)).build()); child.setTag(POSITION_UNCHANGED); + } else { + child.setTag(POSITION_NONE); } container.addView(child); return child; diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PreloadAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PreloadAdapter.java index 113deb4c..251467a2 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PreloadAdapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PreloadAdapter.java @@ -2,65 +2,55 @@ import com.hiroshi.cimoc.model.Chapter; -import java.util.List; - /** * Created by Hiroshi on 2016/7/29. */ public class PreloadAdapter { - private List list; + private Chapter[] array; private int index; private int prev; private int next; - public PreloadAdapter(List list, int index) { - this.list = list; + public PreloadAdapter(Chapter[] array, int index) { + this.array = array; this.index = index; prev = index + 1; next = index; } public Chapter getPrevChapter() { - return prev < list.size() ? list.get(prev) : null; + return prev < array.length ? array[prev] : null; } public Chapter getNextChapter() { - return next >= 0 ? list.get(next) : null; + return next >= 0 ? array[next] : null; } public Chapter prevChapter() { if (++index < prev) { - return list.get(index); + return array[index]; } return null; } public Chapter nextChapter() { if (--index > next) { - return list.get(index); + return array[index]; } return null; } public Chapter movePrev() { - return list.get(prev++); + return array[prev++]; } public Chapter moveNext() { - return list.get(next--); - } - - public int getOffset() { - int offset = 0; - for (int i = prev - 1; i > index; --i) { - offset += list.get(i).getCount(); - } - return offset; + return array[next--]; } public boolean isLoad() { - return index != next; + return prev != next + 1; } } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/custom/LimitedViewPager.java b/app/src/main/java/com/hiroshi/cimoc/ui/custom/LimitedViewPager.java index 00a4f47e..ad568ba5 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/custom/LimitedViewPager.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/custom/LimitedViewPager.java @@ -19,10 +19,16 @@ public class LimitedViewPager extends ViewPager { public LimitedViewPager(Context context, AttributeSet attrs) { super(context, attrs); + init(); } public LimitedViewPager(Context context) { super(context); + init(); + } + + private void init() { + limit = LIMIT_BOTH; } private float lastX; @@ -53,6 +59,18 @@ public boolean dispatchTouchEvent(MotionEvent ev) { } + public void nextPage() { + if (limit != LIMIT_LEFT && limit != LIMIT_BOTH) { + setCurrentItem(getCurrentItem() + 1); + } + } + + public void prevPage() { + if (limit != LIMIT_RIGHT && limit != LIMIT_BOTH) { + setCurrentItem(getCurrentItem() - 1); + } + } + public void setLimit(int limit) { this.limit = limit; } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/AboutFragment.java b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/AboutFragment.java index a49bf001..65c5ae1c 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/AboutFragment.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/AboutFragment.java @@ -24,20 +24,12 @@ public class AboutFragment extends BaseFragment { } } - @Override - protected void initPresenter() {} - @Override protected void initView() { isEnable = CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_EX, false); count = 0; } - @Override - protected BasePresenter getPresenter() { - return null; - } - @Override protected int getLayoutView() { return R.layout.fragment_about; diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/BaseFragment.java b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/BaseFragment.java index 4e2948d6..d28bb432 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/BaseFragment.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/BaseFragment.java @@ -2,8 +2,6 @@ import android.app.Fragment; import android.os.Bundle; -import android.support.annotation.LayoutRes; -import android.support.annotation.Nullable; import android.support.design.widget.Snackbar; import android.view.LayoutInflater; import android.view.View; @@ -18,7 +16,6 @@ */ public abstract class BaseFragment extends Fragment { - @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(getLayoutView(), container, false); @@ -45,12 +42,14 @@ public void showSnackbar(String msg) { } } - protected abstract void initView(); + protected void initView() {} - protected abstract @LayoutRes int getLayoutView(); + protected BasePresenter getPresenter() { + return null; + } - protected abstract BasePresenter getPresenter(); + protected void initPresenter() {} - protected abstract void initPresenter(); + protected abstract int getLayoutView(); } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/CimocFragment.java b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/CimocFragment.java index 03bd3fa8..e4a34b3b 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/CimocFragment.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/CimocFragment.java @@ -13,7 +13,6 @@ import com.hiroshi.cimoc.CimocApplication; import com.hiroshi.cimoc.R; import com.hiroshi.cimoc.core.Kami; -import com.hiroshi.cimoc.presenter.BasePresenter; import com.hiroshi.cimoc.ui.activity.ResultActivity; import com.hiroshi.cimoc.utils.DialogFactory; import com.hiroshi.cimoc.utils.PreferenceMaster; @@ -92,12 +91,4 @@ protected int getLayoutView() { return R.layout.fragment_cimoc; } - @Override - protected void initPresenter() {} - - @Override - protected BasePresenter getPresenter() { - return null; - } - } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SettingsFragment.java b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SettingsFragment.java index f9990699..c3b9c2fd 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SettingsFragment.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SettingsFragment.java @@ -3,6 +3,7 @@ import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.support.v7.app.AlertDialog; +import android.widget.CheckBox; import android.widget.TextView; import com.hiroshi.cimoc.CimocApplication; @@ -20,19 +21,43 @@ */ public class SettingsFragment extends BaseFragment { - @BindView(R.id.settings_other_home_summary) TextView mIndexSummary; + @BindView(R.id.settings_other_home_summary) TextView mHomeSummary; + @BindView(R.id.settings_reader_mode_summary) TextView mModeSummary; + @BindView(R.id.settings_reader_volume_checkbox) CheckBox mVolumeBox; private SettingsPresenter mPresenter; + private PreferenceMaster mPreference; private AlertDialog mProgressDialog; private int mBackupChoice; private int mHomeChoice; + private int mModeChoice; + private int mTempChoice; + private boolean mVolumeChoice; + + private OnClickListener mSingleChoiceListener = new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + mTempChoice = which; + } + }; @Override protected void initView() { + mPreference = CimocApplication.getPreferences(); mProgressDialog = DialogFactory.buildCancelableFalseDialog(getActivity()); - mHomeChoice = CimocApplication.getPreferences().getInt(PreferenceMaster.PREF_HOME, R.id.drawer_cimoc); - mIndexSummary.setText(PreferenceMaster.getTitleById(mHomeChoice)); + mHomeChoice = mPreference.getInt(PreferenceMaster.PREF_HOME, PreferenceMaster.HOME_CIMOC); + mModeChoice = mPreference.getInt(PreferenceMaster.PREF_MODE, PreferenceMaster.MODE_HORIZONTAL_PAGE); + mVolumeChoice = mPreference.getBoolean(PreferenceMaster.PREF_VOLUME, false); + mHomeSummary.setText(getResources().getStringArray(R.array.home_items)[mHomeChoice]); + mModeSummary.setText(getResources().getStringArray(R.array.mode_items)[mModeChoice]); + mVolumeBox.setChecked(mVolumeChoice); + } + + @OnClick(R.id.settings_reader_volume_btn) void onVolumeBtnClick() { + mVolumeChoice = !mVolumeChoice; + mVolumeBox.setChecked(mVolumeChoice); + mPreference.putBoolean(PreferenceMaster.PREF_VOLUME, mVolumeChoice); } @OnClick(R.id.settings_backup_restore_btn) void onRestoreBtnClick() { @@ -41,16 +66,11 @@ protected void initView() { showSnackbar("没有找到备份文件"); return; } - DialogFactory.buildSingleChoiceDialog(getActivity(), R.string.settings_select_file, array, -1, - new OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - mBackupChoice = which; - } - }, + DialogFactory.buildSingleChoiceDialog(getActivity(), R.string.settings_select_file, array, -1, mSingleChoiceListener, new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { + mBackupChoice = mTempChoice; mPresenter.onRestorePositiveBtnClick(array[mBackupChoice]); } }).show(); @@ -58,18 +78,25 @@ public void onClick(DialogInterface dialog, int which) { @OnClick(R.id.settings_other_home_btn) void onHomeBtnClick() { final int[] array = new int[] { R.id.drawer_cimoc, R.id.drawer_favorite, R.id.drawer_history }; - DialogFactory.buildSingleChoiceDialog(getActivity(), R.string.settings_select_home, R.array.index_items, -1, + DialogFactory.buildSingleChoiceDialog(getActivity(), R.string.settings_select_home, R.array.home_items, mHomeChoice, mSingleChoiceListener, new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - mHomeChoice = array[which]; + mHomeChoice = mTempChoice; + mPreference.putInt(PreferenceMaster.PREF_HOME, mHomeChoice); + mHomeSummary.setText(getResources().getStringArray(R.array.home_items)[mHomeChoice]); } - }, + }).show(); + } + + @OnClick(R.id.settings_reader_mode_btn) void onModeBtnClick() { + DialogFactory.buildSingleChoiceDialog(getActivity(), R.string.settings_select_mode, R.array.mode_items, mModeChoice, mSingleChoiceListener, new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - CimocApplication.getPreferences().putInt(PreferenceMaster.PREF_HOME, mHomeChoice); - mIndexSummary.setText(PreferenceMaster.getTitleById(mHomeChoice)); + mModeChoice = mTempChoice; + mPreference.putInt(PreferenceMaster.PREF_HOME, mModeChoice); + mModeSummary.setText(getResources().getStringArray(R.array.mode_items)[mModeChoice]); } }).show(); } diff --git a/app/src/main/java/com/hiroshi/cimoc/utils/ControllerBuilderFactory.java b/app/src/main/java/com/hiroshi/cimoc/utils/ControllerBuilderFactory.java index b8c803fd..187bb733 100644 --- a/app/src/main/java/com/hiroshi/cimoc/utils/ControllerBuilderFactory.java +++ b/app/src/main/java/com/hiroshi/cimoc/utils/ControllerBuilderFactory.java @@ -9,7 +9,6 @@ import com.facebook.imagepipeline.backends.okhttp3.OkHttpImagePipelineConfigFactory; import com.facebook.imagepipeline.core.ImagePipelineConfig; import com.facebook.imagepipeline.core.ImagePipelineFactory; -import com.hiroshi.cimoc.CimocApplication; import com.hiroshi.cimoc.core.Kami; import java.io.IOException; @@ -28,19 +27,27 @@ public class ControllerBuilderFactory { public static PipelineDraweeControllerBuilder getControllerBuilder(int source, Context context) { if (builderArray.get(source) == null) { - ImagePipelineFactory factory = buildFactory(context.getApplicationContext(), source); + ImagePipelineFactory factory; + if (source == Kami.SOURCE_EHENTAI) { + factory = buildFactory(context.getApplicationContext(), source, "igneous=583e748d60dc007822213a471d8e71dcba801b6a55cd0ffe04953e8adb63f294d4b60f303d9182b4276281ac883cec4c48a669db0b6c4914da78073945f49b12583e748d60dc007822213a471d8e71dcba801b6a55cd0ffe04953e8adb63f294d4b60f303d9182b4276281ac883cec4c48a669db0b6c4914da78073945f49b12"); + } else { + factory = buildFactory(context.getApplicationContext(), source, null); + } builderArray.put(source, new PipelineDraweeControllerBuilderSupplier(context.getApplicationContext(), factory).get()); } return builderArray.get(source); } - private static ImagePipelineFactory buildFactory(Context context, final int source) { + private static ImagePipelineFactory buildFactory(Context context, final int source, final String cookie) { OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { String referer = Kami.getRefererById(source); Request.Builder request = chain.request().newBuilder(); request.addHeader("Referer", referer); + if (cookie != null) { + request.header("Cookie", cookie); + } return chain.proceed(request.build()); } }).build(); diff --git a/app/src/main/java/com/hiroshi/cimoc/utils/DialogFactory.java b/app/src/main/java/com/hiroshi/cimoc/utils/DialogFactory.java index 94d56020..08206492 100644 --- a/app/src/main/java/com/hiroshi/cimoc/utils/DialogFactory.java +++ b/app/src/main/java/com/hiroshi/cimoc/utils/DialogFactory.java @@ -6,8 +6,6 @@ import com.hiroshi.cimoc.R; -import butterknife.OnClick; - /** * Created by Hiroshi on 2016/8/4. */ diff --git a/app/src/main/java/com/hiroshi/cimoc/utils/MachiSoup.java b/app/src/main/java/com/hiroshi/cimoc/utils/MachiSoup.java index 977f114a..6f0d02b2 100644 --- a/app/src/main/java/com/hiroshi/cimoc/utils/MachiSoup.java +++ b/app/src/main/java/com/hiroshi/cimoc/utils/MachiSoup.java @@ -77,7 +77,6 @@ public String text(String cssQuery) { try { return element.select(cssQuery).first().text(); } catch (Exception e) { - e.printStackTrace(); } return null; } @@ -105,7 +104,11 @@ public String text(String cssQuery, String regex, int index) { } public String attr(String attr) { - return element.attr(attr); + try { + return element.attr(attr); + } catch (Exception e) { + } + return null; } public String attr(String attr, String regex, int index) { @@ -113,7 +116,11 @@ public String attr(String attr, String regex, int index) { } public String attr(String cssQuery, String attr) { - return element.select(cssQuery).first().attr(attr); + try { + return element.select(cssQuery).first().attr(attr); + } catch (Exception e) { + } + return null; } public String attr(String cssQuery, String attr, String regex, int index) { diff --git a/app/src/main/java/com/hiroshi/cimoc/utils/PreferenceMaster.java b/app/src/main/java/com/hiroshi/cimoc/utils/PreferenceMaster.java index b728b44c..1884a743 100644 --- a/app/src/main/java/com/hiroshi/cimoc/utils/PreferenceMaster.java +++ b/app/src/main/java/com/hiroshi/cimoc/utils/PreferenceMaster.java @@ -10,9 +10,18 @@ */ public class PreferenceMaster { + public static final int MODE_HORIZONTAL_PAGE = 0; + public static final int MODE_HORIZONTAL_STREAM = 1; + public static final int MODE_VERTICAL_STREAM = 2; + + public static final int HOME_CIMOC = 0; + public static final int HOME_FAVORITE = 1; + public static final int HOME_HISTORY = 2; + public static final String PREF_EX = "pref_ex"; public static final String PREF_HOME = "pref_home"; - public static final String PREF_READER = "pref_reader"; + public static final String PREF_MODE = "pref_mode"; + public static final String PREF_VOLUME = "pref_volume"; private static final String PREFERENCES_NAME = "cimoc_preferences"; @@ -54,15 +63,15 @@ public void putLong(String key, long value) { mSharedPreferences.edit().putLong(key, value).apply(); } - public static String getTitleById(int id) { - switch (id) { + public static int getHomeId(int value) { + switch (value) { default: - case R.id.drawer_cimoc: - return "Cimoc"; - case R.id.drawer_favorite: - return "我的漫画"; - case R.id.drawer_history: - return "历史阅读"; + case HOME_CIMOC: + return R.id.drawer_cimoc; + case HOME_FAVORITE: + return R.id.drawer_favorite; + case HOME_HISTORY: + return R.id.drawer_history; } } diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml index cfa6d27e..f2589fb4 100644 --- a/app/src/main/res/layout/fragment_settings.xml +++ b/app/src/main/res/layout/fragment_settings.xml @@ -1,150 +1,204 @@ - + android:layout_height="match_parent" + android:scrollbars="none"> - + android:layout_height="match_parent"> - + android:layout_height="wrap_content"> - - - + - + + + + + android:gravity="center_vertical" + android:padding="16dp" + android:clickable="true" + android:background="?android:attr/selectableItemBackground"> + + + - - - - + android:layout_height="wrap_content"> - - - + - + + + + + android:gravity="center_vertical" + android:padding="16dp" + android:clickable="true" + android:background="?android:attr/selectableItemBackground"> + + + + + android:layout_height="wrap_content"> - + + + + + + android:gravity="center_vertical" + android:padding="16dp" + android:clickable="true" + android:background="?android:attr/selectableItemBackground"> + + + - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/item_comic.xml b/app/src/main/res/layout/item_comic.xml index 9616e304..b021202f 100644 --- a/app/src/main/res/layout/item_comic.xml +++ b/app/src/main/res/layout/item_comic.xml @@ -23,6 +23,7 @@ android:visibility="invisible" android:padding="2dp" android:text="@string/comic_new" + android:textStyle="bold" android:textColor="?colorAccent" android:textSize="10sp"/> 动漫之家 - Dmzj 汗汗漫画 - HHAAZZ CC图库 - CCTuku - E站 - EHentai + Ex绅士 - ExHentai - + Cimoc 我的漫画 历史阅读 + + 竖屏翻页模式 + 竖屏卷纸模式 + 横屏卷纸模式 + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 39377b53..01e4cad3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -37,12 +37,16 @@ 备份到本地文件 恢复 从本地文件中恢复 + 阅读设置 + 阅读模式 + 音量键翻页 + 仅限翻页模式 其他设置 首页设置 清除缓存 - 阅读模式 首页选择 + 阅读模式选择 文件选择 源代码 From 856ec9f41abd77a3cbbc69cc7a65f01be9a6ad2b Mon Sep 17 00:00:00 2001 From: hiroshi Date: Sun, 7 Aug 2016 23:56:34 +0800 Subject: [PATCH 005/521] =?UTF-8?q?=E5=AE=8C=E6=88=90=E5=8D=B7=E7=BA=B8?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=20=E5=8A=A0=E5=85=A5=E5=A4=9C=E9=97=B4?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/misc.xml | 2 +- app/src/main/AndroidManifest.xml | 18 +- .../java/com/hiroshi/cimoc/core/CCTuku.java | 8 +- .../java/com/hiroshi/cimoc/core/Dmzj.java | 2 +- .../java/com/hiroshi/cimoc/core/Kami.java | 29 ++- .../cimoc/presenter/DetailPresenter.java | 2 +- .../cimoc/presenter/MainPresenter.java | 1 - .../cimoc/presenter/ReaderPresenter.java | 58 +++-- .../cimoc/presenter/ResultPresenter.java | 2 +- .../cimoc/presenter/SettingsPresenter.java | 18 +- .../presenter/StreamReaderPresenter.java | 135 ------------ .../cimoc/ui/activity/BaseActivity.java | 46 +++- .../cimoc/ui/activity/DetailActivity.java | 18 +- .../cimoc/ui/activity/PageReaderActivity.java | 201 ++++++------------ .../cimoc/ui/activity/ReaderActivity.java | 138 ++++++++++-- .../cimoc/ui/activity/ResultActivity.java | 6 +- .../ui/activity/StreamReaderActivity.java | 123 ++++++----- .../cimoc/ui/adapter/ChapterAdapter.java | 5 +- .../cimoc/ui/adapter/ComicAdapter.java | 3 +- .../cimoc/ui/adapter/PicturePageAdapter.java | 7 +- .../ui/adapter/PictureStreamAdapter.java | 20 +- .../cimoc/ui/adapter/ResultAdapter.java | 2 +- .../cimoc/ui/custom/LimitedViewPager.java | 44 ++-- .../ui/custom/photo/PhotoDraweeView.java | 8 + .../photo/PhotoDraweeViewController.java | 19 +- .../cimoc/ui/fragment/BaseFragment.java | 4 + .../cimoc/ui/fragment/CimocFragment.java | 5 +- .../cimoc/ui/fragment/FavoriteFragment.java | 2 +- .../cimoc/ui/fragment/SettingsFragment.java | 24 ++- .../cimoc/utils/ControllerBuilderFactory.java | 2 +- .../java/com/hiroshi/cimoc/utils/ExLog.java | 2 +- .../hiroshi/cimoc/utils/PreferenceMaster.java | 1 + .../ic_navigate_before_white_24dp.png | Bin 0 -> 132 bytes .../ic_navigate_before_white_24dp.png | Bin 0 -> 136 bytes .../ic_navigate_before_white_24dp.png | Bin 0 -> 202 bytes .../res/drawable/button_chapter_selector.xml | 2 +- ...ty_reader.xml => activity_page_reader.xml} | 26 +-- .../res/layout/activity_stream_reader.xml | 26 +-- app/src/main/res/layout/custom_back_btn.xml | 18 ++ ...tem_picture_msg.xml => custom_loading.xml} | 5 +- app/src/main/res/layout/custom_seek_bar.xml | 26 +++ app/src/main/res/layout/fragment_about.xml | 28 +++ app/src/main/res/layout/fragment_cimoc.xml | 2 +- app/src/main/res/layout/fragment_settings.xml | 33 +++ app/src/main/res/layout/item_comic.xml | 2 +- app/src/main/res/values/arrays.xml | 1 + app/src/main/res/values/colors.xml | 5 +- app/src/main/res/values/strings.xml | 51 ++++- 48 files changed, 666 insertions(+), 514 deletions(-) delete mode 100644 app/src/main/java/com/hiroshi/cimoc/presenter/StreamReaderPresenter.java create mode 100644 app/src/main/res/drawable-hdpi/ic_navigate_before_white_24dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_navigate_before_white_24dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_navigate_before_white_24dp.png rename app/src/main/res/layout/{activity_reader.xml => activity_page_reader.xml} (63%) create mode 100644 app/src/main/res/layout/custom_back_btn.xml rename app/src/main/res/layout/{item_picture_msg.xml => custom_loading.xml} (78%) create mode 100644 app/src/main/res/layout/custom_seek_bar.xml diff --git a/.idea/misc.xml b/.idea/misc.xml index fbb68289..5d199810 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -37,7 +37,7 @@ - + diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4be82430..cedafbaf 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,4 +1,5 @@ - @@ -13,8 +14,7 @@ android:theme="@style/AppTheme"> + android:name=".ui.activity.MainActivity"> @@ -22,22 +22,18 @@ + android:name=".ui.activity.ResultActivity"/> + android:name=".ui.activity.DetailActivity"/> + android:theme="@style/ReaderTheme"/> + android:theme="@style/ReaderTheme"/> diff --git a/app/src/main/java/com/hiroshi/cimoc/core/CCTuku.java b/app/src/main/java/com/hiroshi/cimoc/core/CCTuku.java index 95cd6217..daec375d 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/CCTuku.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/CCTuku.java @@ -79,15 +79,15 @@ protected Request buildBrowseRequest(String cid, String path) { @Override protected String[] parseBrowse(String html) { - String packed = MachiSoup.match("eval(.*?)\\n;", html, 1); - if (packed != null) { + String[] rs = MachiSoup.match("serverUrl = '(.*?)'[\\s\\S]*?eval(.*?)\\n;", html, 1, 2); + if (rs != null) { try { - String result = Decryption.evalDecrypt(packed); + String result = Decryption.evalDecrypt(rs[1]); String[] array = MachiSoup.match("pic_url='(.*?)';.*?tpf=(\\d+?);.*pages=(\\d+?);.*?pid=(.*?);.*?pic_extname='(.*?)';", result, 1, 2, 3, 4, 5); if (array != null) { int tpf = Integer.parseInt(array[1]) + 1; int pages = Integer.parseInt(array[2]); - String format = "http://tkpic.um5.cc/" + array[3] + "/" + array[0] + "/%0" + tpf + "d." + array[4]; + String format = rs[0] + "/" + array[3] + "/" + array[0] + "/%0" + tpf + "d." + array[4]; String[] images = new String[pages]; for (int i = 0; i != pages; ++i) { images[i] = String.format(Locale.CHINA, format, i + 1); diff --git a/app/src/main/java/com/hiroshi/cimoc/core/Dmzj.java b/app/src/main/java/com/hiroshi/cimoc/core/Dmzj.java index 547df5e4..cb7541c7 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/Dmzj.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/Dmzj.java @@ -108,7 +108,7 @@ protected Request buildBrowseRequest(String cid, String path) { @Override protected String[] parseBrowse(String html) { - String jsonString = MachiSoup.match("\"page_url\":(\\[.*?\\])", html, 1); + String jsonString = MachiSoup.match("\"page_url\":(\\[.*?\\]),", html, 1); if (jsonString != null) { try { JSONArray array = new JSONArray(jsonString); diff --git a/app/src/main/java/com/hiroshi/cimoc/core/Kami.java b/app/src/main/java/com/hiroshi/cimoc/core/Kami.java index 0290391c..e075223e 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/Kami.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/Kami.java @@ -1,5 +1,6 @@ package com.hiroshi.cimoc.core; +import com.hiroshi.cimoc.R; import com.hiroshi.cimoc.core.base.Manga; /** @@ -12,24 +13,27 @@ public class Kami { public static final int SOURCE_HHAAZZ = 2; public static final int SOURCE_CCTUKU = 3; public static final int SOURCE_EHENTAI = 100; + public static final int SOURCE_EXHENTAI = 101; - public static String getSourceById(int id) { + public static int getSourceTitle(int id) { switch (id) { default: case SOURCE_IKANMAN: - return "看漫画"; + return R.string.source_ikanman; case SOURCE_DMZJ: - return "动漫之家"; + return R.string.source_dmzj; case SOURCE_HHAAZZ: - return "汗汗漫画"; + return R.string.source_hhaazz; case SOURCE_CCTUKU: - return "CC图库"; + return R.string.source_cctuku; case SOURCE_EHENTAI: - return "ExHentai"; + return R.string.source_ehentai; + case SOURCE_EXHENTAI: + return R.string.source_exhentai; } } - public static String getRefererById(int id) { + public static String getReferer(int id) { switch (id) { default: case SOURCE_IKANMAN: @@ -41,13 +45,15 @@ public static String getRefererById(int id) { case SOURCE_CCTUKU: return "http://m.tuku.cc"; case SOURCE_EHENTAI: + return "http://lofi.e-hentai.org"; + case SOURCE_EXHENTAI: return "https://exhentai.org"; } } - private static Manga mIkanman, mDmzj, mHHAAZZ, mCCTuku, mExHentai; + private static Manga mIkanman, mDmzj, mHHAAZZ, mCCTuku, mExHentai, mEHentai; - public static Manga getMangaById(int id) { + public static Manga getManga(int id) { switch (id) { default: case SOURCE_IKANMAN: @@ -71,6 +77,11 @@ public static Manga getMangaById(int id) { } return mCCTuku; case SOURCE_EHENTAI: + if (mEHentai == null) { + mEHentai = new EHentai(); + } + return mEHentai; + case SOURCE_EXHENTAI: if (mExHentai == null) { mExHentai = new ExHentai(); } diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/DetailPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/DetailPresenter.java index 45857d85..f4398a60 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/DetailPresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/DetailPresenter.java @@ -30,7 +30,7 @@ public class DetailPresenter extends BasePresenter { public DetailPresenter(DetailActivity activity, Long id, int source, String cid) { mDetailActivity = activity; mComicManager = ComicManager.getInstance(); - mManga = Kami.getMangaById(source); + mManga = Kami.getManga(source); mComic = mComicManager.getComic(id, source, cid); } diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/MainPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/MainPresenter.java index bef94e18..6c58718f 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/MainPresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/MainPresenter.java @@ -115,7 +115,6 @@ public boolean onNavigationItemSelected(MenuItem menuItem) { @Subscribe(threadMode = ThreadMode.MAIN) public void onEvent(EventMessage msg) { - } } diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/ReaderPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/ReaderPresenter.java index 7a7b6408..3258634d 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/ReaderPresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/ReaderPresenter.java @@ -1,10 +1,11 @@ package com.hiroshi.cimoc.presenter; +import com.hiroshi.cimoc.R; import com.hiroshi.cimoc.core.Kami; import com.hiroshi.cimoc.core.base.Manga; import com.hiroshi.cimoc.model.Chapter; import com.hiroshi.cimoc.model.EventMessage; -import com.hiroshi.cimoc.ui.activity.PageReaderActivity; +import com.hiroshi.cimoc.ui.activity.ReaderActivity; import com.hiroshi.cimoc.ui.adapter.PreloadAdapter; import org.greenrobot.eventbus.EventBus; @@ -20,19 +21,26 @@ public class ReaderPresenter extends BasePresenter { private final static int LOAD_PREV = 1; private final static int LOAD_NEXT = 2; - private PageReaderActivity mPageReaderActivity; + private ReaderActivity mReaderActivity; private PreloadAdapter mPreloadAdapter; private Manga mManga; + private boolean isShowNext; + private boolean isShowPrev; + private int count; + private String cid; private String last; private Integer page; private int status; - public ReaderPresenter(PageReaderActivity activity, int source, String cid, String last, Integer page, Chapter[] array, int position) { - mPageReaderActivity = activity; + public ReaderPresenter(ReaderActivity activity, int source, String cid, String last, Integer page, Chapter[] array, int position) { + mReaderActivity = activity; mPreloadAdapter = new PreloadAdapter(array, position); - mManga = Kami.getMangaById(source); + mManga = Kami.getManga(source); + isShowNext = true; + isShowPrev = true; + count = 0; this.cid = cid; this.last = last; this.page = page; @@ -58,44 +66,52 @@ public void setPage(int progress) { } public void loadNext() { - if (status == LOAD_NULL) { + if (status == LOAD_NULL && isShowNext) { Chapter chapter = mPreloadAdapter.getNextChapter(); if (chapter != null) { status = LOAD_NEXT; mManga.browse(cid, chapter.getPath()); - mPageReaderActivity.showToast("正在加载下一话"); + mReaderActivity.showToast(R.string.reader_load_next); } else { - mPageReaderActivity.showToast("后面没有了"); + isShowNext = false; + mReaderActivity.showToast(R.string.reader_next_none); } } } public void loadPrev() { - if (status == LOAD_NULL) { + if (status == LOAD_NULL && isShowPrev) { Chapter chapter = mPreloadAdapter.getPrevChapter(); if (chapter != null) { status = LOAD_PREV; mManga.browse(cid, chapter.getPath()); - mPageReaderActivity.showToast("正在加载上一话"); + mReaderActivity.showToast(R.string.reader_load_prev); } else { - mPageReaderActivity.showToast("前面没有了"); + isShowPrev = false; + mReaderActivity.showToast(R.string.reader_prev_none); } } } public void onChapterToNext() { Chapter chapter = mPreloadAdapter.nextChapter(); + if (chapter == null) { + return; + } switchChapter(1, chapter.getCount(), chapter.getTitle(), chapter.getPath()); } public void onChapterToPrev() { Chapter chapter = mPreloadAdapter.prevChapter(); + if (chapter == null) { + return; + } switchChapter(chapter.getCount(), chapter.getCount(), chapter.getTitle(), chapter.getPath()); } private void switchChapter(int progress, int count, String title, String path) { - mPageReaderActivity.updateChapterInfo(count, title); - mPageReaderActivity.setReadProgress(progress); + mReaderActivity.updateChapterInfo(count, title); + mReaderActivity.setReadProgress(progress); EventBus.getDefault().post(new EventMessage(EventMessage.COMIC_LAST_CHANGE, path)); } @@ -106,30 +122,32 @@ public void onEvent(EventMessage msg) { String[] array = (String[]) msg.getData(); Chapter chapter; if (!mPreloadAdapter.isLoad()) { - mPageReaderActivity.setNextImage(array); + mReaderActivity.setNextImage(array); chapter = mPreloadAdapter.moveNext(); if (!chapter.getPath().equals(last) || page == null) { page = 1; } - mPageReaderActivity.initLoad(page, array.length, chapter.getTitle()); + mReaderActivity.initLoad(page, array.length, chapter.getTitle()); EventBus.getDefault().post(new EventMessage(EventMessage.COMIC_LAST_CHANGE, chapter.getPath())); } else { if (status == LOAD_PREV) { - mPageReaderActivity.setPrevImage(array); + mReaderActivity.setPrevImage(array); chapter = mPreloadAdapter.movePrev(); } else { - mPageReaderActivity.setNextImage(array); + mReaderActivity.setNextImage(array); chapter = mPreloadAdapter.moveNext(); } - mPageReaderActivity.loadSuccess(status == LOAD_NEXT); - mPageReaderActivity.showToast("加载成功"); + mReaderActivity.loadSuccess(status == LOAD_NEXT); } chapter.setCount(array.length); status = LOAD_NULL; break; case EventMessage.PARSE_PIC_FAIL: case EventMessage.NETWORK_ERROR: - mPageReaderActivity.showToast("加载错误"); + mReaderActivity.showToast(R.string.reader_load_error); + if (++count < 2) { + status = LOAD_NULL; + } break; } } diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/ResultPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/ResultPresenter.java index 70a0a277..49d436bf 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/ResultPresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/ResultPresenter.java @@ -26,7 +26,7 @@ public class ResultPresenter extends BasePresenter { public ResultPresenter(ResultActivity activity, int source, String keyword) { this.mResultActivity = activity; - this.mManga = Kami.getMangaById(source); + this.mManga = Kami.getManga(source); this.keyword = keyword; this.page = 0; this.isLoading = false; diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/SettingsPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/SettingsPresenter.java index a984dd69..ba1334b7 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/SettingsPresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/SettingsPresenter.java @@ -1,5 +1,6 @@ package com.hiroshi.cimoc.presenter; +import com.hiroshi.cimoc.R; import com.hiroshi.cimoc.core.ComicManager; import com.hiroshi.cimoc.model.Comic; import com.hiroshi.cimoc.model.EventMessage; @@ -26,19 +27,20 @@ public SettingsPresenter(SettingsFragment fragment) { } public void onCacheBtnClick() { - mSettingsFragment.showProgressDialog("正在删除.."); + mSettingsFragment.showProgressDialog(R.string.settings_other_cache_doing); FileUtils.deleteDir(mSettingsFragment.getActivity().getCacheDir()); - mSettingsFragment.showSnackbar("删除成功"); + mSettingsFragment.showSnackbar(R.string.settings_other_cache_success); mSettingsFragment.hideProgressDialog(); } public void onBackupBtnClick() { - mSettingsFragment.showProgressDialog("正在备份.."); + mSettingsFragment.showProgressDialog(R.string.settings_backup_save_doing); List list = mComicManager.listBackup(); if (BackupUtils.saveComic(list)) { - mSettingsFragment.showSnackbar("备份成功 共 " + list.size() + " 条记录"); + String text = mSettingsFragment.getString(R.string.settings_backup_save_success) + list.size(); + mSettingsFragment.showSnackbar(text); } else { - mSettingsFragment.showSnackbar("备份失败 共 " + list.size() + " 条记录"); + mSettingsFragment.showSnackbar(R.string.settings_backup_save_fail); } mSettingsFragment.hideProgressDialog(); } @@ -52,18 +54,20 @@ public String[] getFiles() { } public void onRestorePositiveBtnClick(String name) { - mSettingsFragment.showProgressDialog("正在恢复.."); + mSettingsFragment.showProgressDialog(R.string.settings_backup_restore_doing); List list = BackupUtils.restoreComic(name); mComicManager.restoreFavorite(list); } + @SuppressWarnings("unchecked") @Subscribe(threadMode = ThreadMode.MAIN) public void onEvent(EventMessage msg) { switch (msg.getType()) { case EventMessage.RESTORE_FAVORITE: List list = (List) msg.getData(); mSettingsFragment.hideProgressDialog(); - mSettingsFragment.showSnackbar("恢复成功 共 " + list.size() + " 条记录"); + String text = mSettingsFragment.getString(R.string.settings_backup_restore_success) + list.size(); + mSettingsFragment.showSnackbar(text); break; } } diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/StreamReaderPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/StreamReaderPresenter.java deleted file mode 100644 index 8f65e299..00000000 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/StreamReaderPresenter.java +++ /dev/null @@ -1,135 +0,0 @@ -package com.hiroshi.cimoc.presenter; - -import android.util.Log; - -import com.hiroshi.cimoc.core.Kami; -import com.hiroshi.cimoc.core.base.Manga; -import com.hiroshi.cimoc.model.Chapter; -import com.hiroshi.cimoc.model.EventMessage; -import com.hiroshi.cimoc.ui.activity.StreamReaderActivity; -import com.hiroshi.cimoc.ui.adapter.PreloadAdapter; - -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.ThreadMode; - -/** - * Created by Hiroshi on 2016/8/5. - */ -public class StreamReaderPresenter extends BasePresenter { - - private final static int LOAD_NULL = 0; - private final static int LOAD_PREV = 1; - private final static int LOAD_NEXT = 2; - - private StreamReaderActivity mStreamReaderActivity; - private PreloadAdapter mPreloadAdapter; - private Manga mManga; - - private String cid; - private String last; - private Integer page; - private int status; - - public StreamReaderPresenter(StreamReaderActivity activity, int source, String cid, String last, Integer page, Chapter[] array, int position) { - mStreamReaderActivity = activity; - mPreloadAdapter = new PreloadAdapter(array, position); - mManga = Kami.getMangaById(source); - this.cid = cid; - this.last = last; - this.page = page; - } - - @Override - public void onCreate() { - super.onCreate(); - status = LOAD_NEXT; - mManga.browse(cid, mPreloadAdapter.getNextChapter().getPath()); - } - - @Override - public void onDestroy() { - super.onDestroy(); - mManga.cancel(); - } - - public void loadNext() { - if (status == LOAD_NULL) { - Chapter chapter = mPreloadAdapter.getNextChapter(); - if (chapter != null) { - status = LOAD_NEXT; - mManga.browse(cid, chapter.getPath()); - } - } - } - - public void onScrolled(int dy, int last, int count) { - if (last >= count - 1 && dy > 0 && status == LOAD_NULL) { - Chapter chapter = mPreloadAdapter.getNextChapter(); - if (chapter != null) { - status = LOAD_NEXT; - mManga.browse(cid, chapter.getPath()); - } - } - /*else if (last <= 1 && dy < 0 && status == LOAD_NULL) { - Chapter chapter = mPreloadAdapter.getPrevChapter(); - if (chapter != null) { - status = LOAD_PREV; - mManga.browse(cid, chapter.getPath()); - } - }*/ - } - - public void setPage(int progress) { - EventBus.getDefault().post(new EventMessage(EventMessage.COMIC_PAGE_CHANGE, progress)); - } - - public void onChapterToNext() { - Chapter chapter = mPreloadAdapter.nextChapter(); - if (chapter != null) { - switchChapter(1, chapter.getCount(), chapter.getTitle(), chapter.getPath()); - } - } - - public void onChapterToPrev() { - Chapter chapter = mPreloadAdapter.prevChapter(); - if (chapter != null) { - switchChapter(chapter.getCount(), chapter.getCount(), chapter.getTitle(), chapter.getPath()); - } - } - - public void onProgressChanged(int value, boolean fromUser) { - } - - private void switchChapter(int progress, int max, String title, String path) { - mStreamReaderActivity.updateChapterInfo(max, title); - if (progress != -1) { - mStreamReaderActivity.setReadProgress(progress); - } - EventBus.getDefault().post(new EventMessage(EventMessage.COMIC_LAST_CHANGE, path)); - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEvent(EventMessage msg) { - switch (msg.getType()) { - case EventMessage.PARSE_PIC_SUCCESS: - String[] array = (String[]) msg.getData(); - Chapter chapter; - if (status == LOAD_PREV) { - mStreamReaderActivity.setPrevImage(array); - chapter = mPreloadAdapter.movePrev(); - } else { - mStreamReaderActivity.setNextImage(array); - chapter = mPreloadAdapter.moveNext(); - } - chapter.setCount(array.length); - switchChapter(1, array.length, chapter.getTitle(), chapter.getPath()); - status = LOAD_NULL; - break; - case EventMessage.PARSE_PIC_FAIL: - case EventMessage.NETWORK_ERROR: - break; - } - } - -} diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/BaseActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/BaseActivity.java index a49b4e88..e249deb7 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/BaseActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/BaseActivity.java @@ -1,14 +1,20 @@ package com.hiroshi.cimoc.ui.activity; +import android.content.Context; +import android.content.pm.ActivityInfo; +import android.graphics.PixelFormat; import android.os.Bundle; import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.View; -import android.widget.Toast; +import android.view.WindowManager; +import android.widget.FrameLayout; +import com.hiroshi.cimoc.CimocApplication; import com.hiroshi.cimoc.R; import com.hiroshi.cimoc.presenter.BasePresenter; +import com.hiroshi.cimoc.utils.PreferenceMaster; import butterknife.ButterKnife; @@ -17,13 +23,21 @@ */ public abstract class BaseActivity extends AppCompatActivity { + private View nightlyView; + protected Toolbar mToolbar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + if (isPortrait()) { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + } else { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); + } setContentView(getLayoutRes()); ButterKnife.bind(this); + initNightly(); initToolbar(); initPresenter(); initView(); @@ -40,6 +54,15 @@ protected void onDestroy() { } } + private void initNightly() { + nightlyView = new FrameLayout(this); + nightlyView.setBackgroundColor(getResources().getColor(R.color.trans_black)); + boolean nightly = CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_NIGHTLY, false); + if (nightly) { + nightlyOn(); + } + } + protected void initToolbar() { mToolbar = (Toolbar) findViewById(R.id.custom_toolbar); mToolbar.setTitle(getDefaultTitle()); @@ -49,6 +72,19 @@ protected void initToolbar() { } } + public void nightlyOn() { + WindowManager.LayoutParams params = new WindowManager.LayoutParams( + WindowManager.LayoutParams.MATCH_PARENT,WindowManager.LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.TYPE_APPLICATION, + WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, + PixelFormat.TRANSLUCENT); + ((WindowManager)getSystemService(Context.WINDOW_SERVICE)).addView(nightlyView, params); + } + + public void nightlyOff() { + ((WindowManager)getSystemService(Context.WINDOW_SERVICE)).removeView(nightlyView); + } + protected View getLayoutView() { return null; } @@ -61,6 +97,10 @@ protected BasePresenter getPresenter() { return null; } + protected boolean isPortrait() { + return true; + } + protected void initPresenter() {} protected void initView() {} @@ -74,8 +114,8 @@ public void showSnackbar(String msg) { } } - public void showToast(String msg) { - Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); + public void showSnackbar(int resId) { + showSnackbar(getString(resId)); } } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/DetailActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/DetailActivity.java index 3fd82465..12d02cd9 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/DetailActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/DetailActivity.java @@ -39,11 +39,11 @@ public class DetailActivity extends BaseActivity { if (mPresenter.isComicFavorite()) { mPresenter.unfavoriteComic(); mStarButton.setImageResource(R.drawable.ic_favorite_border_white_24dp); - showSnackbar("取消收藏成功"); + showSnackbar(R.string.detail_unfavorite); } else { mPresenter.favoriteComic(); mStarButton.setImageResource(R.drawable.ic_favorite_white_24dp); - showSnackbar("收藏成功"); + showSnackbar(R.string.detail_favorite); } } @@ -77,7 +77,7 @@ protected int getLayoutRes() { @Override protected String getDefaultTitle() { - return "详情"; + return getString(R.string.detail); } @Override @@ -97,18 +97,18 @@ public void setLastChapter(String last) { public void setView(Comic comic, List list) { if (list == null) { mProgressBar.setVisibility(View.GONE); - showSnackbar("网络错误"); + mCoordinatorLayout.setVisibility(View.VISIBLE); + showSnackbar(R.string.common_network_error); return; } mChapterAdapter = new ChapterAdapter(this, list, comic.getSource(), comic.getCover(), comic.getTitle(), - comic.getAuthor(), comic.getIntro(), comic.getStatus(), comic.getUpdate()); - mChapterAdapter.setLast(comic.getLast()); + comic.getAuthor(), comic.getIntro(), comic.getStatus(), comic.getUpdate(), comic.getLast()); mChapterAdapter.setOnItemClickListener(new BaseAdapter.OnItemClickListener() { @Override public void onItemClick(View view, int position) { if (position != 0) { - Intent intent = PageReaderActivity.createIntent(DetailActivity.this, mPresenter.getComic(), + Intent intent = ReaderActivity.createIntent(DetailActivity.this, mPresenter.getComic(), mChapterAdapter.getDateSet(), position - 1); startActivity(intent); } @@ -125,10 +125,10 @@ public void onItemClick(View view, int position) { mStarButton.setImageResource(R.drawable.ic_favorite_border_white_24dp); } mProgressBar.setVisibility(View.GONE); - mStarButton.setVisibility(View.VISIBLE); mCoordinatorLayout.setVisibility(View.VISIBLE); + mStarButton.setVisibility(View.VISIBLE); if (list.isEmpty()) { - showSnackbar("解析错误或此漫画已被屏蔽"); + showSnackbar(R.string.detail_error); } } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/PageReaderActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/PageReaderActivity.java index e68bfeae..50550495 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/PageReaderActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/PageReaderActivity.java @@ -1,49 +1,35 @@ package com.hiroshi.cimoc.ui.activity; -import android.content.Context; -import android.content.Intent; import android.graphics.Point; import android.support.v4.view.ViewPager; +import android.support.v4.view.ViewPager.OnPageChangeListener; import android.view.KeyEvent; -import android.view.View; import com.hiroshi.cimoc.CimocApplication; import com.hiroshi.cimoc.R; -import com.hiroshi.cimoc.model.Chapter; -import com.hiroshi.cimoc.model.Comic; -import com.hiroshi.cimoc.presenter.BasePresenter; -import com.hiroshi.cimoc.presenter.ReaderPresenter; import com.hiroshi.cimoc.ui.adapter.PicturePageAdapter; import com.hiroshi.cimoc.ui.custom.LimitedViewPager; -import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeViewController; +import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeView; import com.hiroshi.cimoc.utils.ControllerBuilderFactory; import com.hiroshi.cimoc.utils.PreferenceMaster; import org.adw.library.widgets.discreteseekbar.DiscreteSeekBar; import java.util.LinkedList; -import java.util.List; import butterknife.BindView; /** * Created by Hiroshi on 2016/7/7. */ -public class PageReaderActivity extends ReaderActivity { +public class PageReaderActivity extends ReaderActivity implements OnPageChangeListener { @BindView(R.id.reader_view_pager) LimitedViewPager mViewPager; private PicturePageAdapter mPageAdapter; - private ReaderPresenter mPresenter; private boolean volume; - @Override - protected void onPause() { - super.onPause(); - mPresenter.setPage(progress); - } - @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (volume) { @@ -61,139 +47,109 @@ public boolean onKeyDown(int keyCode, KeyEvent event) { @Override protected void initView() { + super.initView(); volume = CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_VOLUME, false); - progress = max = 1; - mPageAdapter = new PicturePageAdapter(new LinkedList(), getLayoutInflater(), - new PhotoDraweeViewController.OnSingleTapListener() { - @Override - public void onSingleTap(View view, float x, float y) { - Point point = new Point(); - getWindowManager().getDefaultDisplay().getSize(point); - float limitX = point.x / 3.0f; - float limitY = point.y / 3.0f; - if (x < limitX) { - mViewPager.prevPage(); - } else if (x > 2 * limitX) { - mViewPager.nextPage(); - } else if (y >= 2 * limitY) { - if (mToolLayout.isShown()) { - mToolLayout.setVisibility(View.VISIBLE); - } else { - mSeekBar.setProgress(progress); - mSeekBar.setMax(max); - mToolLayout.setVisibility(View.VISIBLE); - } - } - } - }, ControllerBuilderFactory.getControllerBuilder(getIntent().getIntExtra(EXTRA_SOURCE, -1), this)); - - mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { - @Override - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {} - - @Override - public void onPageSelected(int position) { - int current = mPageAdapter.getCurrent(); - if (position == current) { - return; - } - mPageAdapter.setCurrent(position); - if (mPageAdapter.isToLeft()) { - mViewPager.setLimit(LimitedViewPager.LIMIT_RIGHT); - } else if (mPageAdapter.isToRight()) { - mViewPager.setLimit(LimitedViewPager.LIMIT_LEFT); - } else { - mViewPager.setLimit(LimitedViewPager.LIMIT_NONE); - } - if (position > current && progress == max) { - mPresenter.onChapterToNext(); - } else if (position < current && progress == 1) { - mPresenter.onChapterToPrev(); - } else { - setReadProgress(progress + position - current); - } - } - - @Override - public void onPageScrollStateChanged(int state) { - switch (state) { - case ViewPager.SCROLL_STATE_DRAGGING: - if (mToolLayout.isShown()) { - mToolLayout.setVisibility(View.INVISIBLE); - } - break; - case ViewPager.SCROLL_STATE_IDLE: - if (mViewPager.getLimit() == LimitedViewPager.LIMIT_RIGHT) { - mPresenter.loadPrev(); - } else if (mViewPager.getLimit() == LimitedViewPager.LIMIT_LEFT) { - mPresenter.loadNext(); - } - break; - } - } - }); + ControllerBuilderFactory.getControllerBuilder(source, this), this); + mViewPager.addOnPageChangeListener(this); mViewPager.setAdapter(mPageAdapter); mViewPager.setCurrentItem(PicturePageAdapter.MAX_COUNT / 2 + 1, false); mViewPager.setOffscreenPageLimit(3); + } - mSeekBar.setOnProgressChangeListener(new DiscreteSeekBar.OnProgressChangeListener() { - @Override - public void onProgressChanged(DiscreteSeekBar seekBar, int value, boolean fromUser) { - if (fromUser) { - mViewPager.setCurrentItem(mPageAdapter.getCurrent() + value - progress, false); - } - } + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {} - @Override - public void onStartTrackingTouch(DiscreteSeekBar seekBar) {} + @Override + public void onPageSelected(int position) { + int current = mPageAdapter.getCurrent(); + if (position == current) { + return; + } + mPageAdapter.setCurrent(position); + if (mPageAdapter.isToLeft()) { + mViewPager.setLimit(LimitedViewPager.LIMIT_RIGHT); + } else if (mPageAdapter.isToRight()) { + mViewPager.setLimit(LimitedViewPager.LIMIT_LEFT); + } else { + mViewPager.setLimit(LimitedViewPager.LIMIT_NONE); + } + if (position > current && progress == max) { + mPresenter.onChapterToNext(); + } else if (position < current && progress == 1) { + mPresenter.onChapterToPrev(); + } else { + setReadProgress(progress + position - current); + } + } - @Override - public void onStopTrackingTouch(DiscreteSeekBar seekBar) {} - }); + @Override + public void onPageScrollStateChanged(int state) { + switch (state) { + case ViewPager.SCROLL_STATE_DRAGGING: + hideToolLayout(); + break; + case ViewPager.SCROLL_STATE_IDLE: + if (mViewPager.getLimit() == LimitedViewPager.LIMIT_LEFT) { + mPresenter.loadNext(); + } + break; + } } @Override - protected void initPresenter() { - int source = getIntent().getIntExtra(EXTRA_SOURCE, -1); - String cid = getIntent().getStringExtra(EXTRA_CID); - String last = getIntent().getStringExtra(EXTRA_LAST); - int page = getIntent().getIntExtra(EXTRA_PAGE, -1); - String[] title = getIntent().getStringArrayExtra(EXTRA_TITLE); - String[] path = getIntent().getStringArrayExtra(EXTRA_PATH); - Chapter[] array = fromArray(title, path); - int position = getIntent().getIntExtra(EXTRA_POSITION, 0); - mPresenter = new ReaderPresenter(this, source, cid, last, page, array, position); + public void onProgressChanged(DiscreteSeekBar seekBar, int value, boolean fromUser) { + if (fromUser) { + mViewPager.setCurrentItem(mPageAdapter.getCurrent() + value - progress); + } } @Override - protected BasePresenter getPresenter() { - return mPresenter; + public void onSingleTap(PhotoDraweeView draweeView, float x, float y) { + Point point = new Point(); + getWindowManager().getDefaultDisplay().getSize(point); + float limitX = point.x / 3.0f; + float limitY = point.y / 3.0f; + if (x < limitX) { + mViewPager.prevPage(); + } else if (x > 2 * limitX) { + mViewPager.nextPage(); + } else if (y >= 2 * limitY) { + switchToolLayout(); + } else if (y >= limitY) { + draweeView.retry(); + } else if (mPageAdapter.isToLeft()) { + mPresenter.loadPrev(); + } } @Override protected int getLayoutRes() { - return R.layout.activity_reader; + return R.layout.activity_page_reader; } + @Override public void setPrevImage(String[] array) { mPageAdapter.setPrevImages(array); } + @Override public void setNextImage(String[] array) { mPageAdapter.setNextImages(array); } + @Override public void loadSuccess(boolean isNext) { if (isNext && mViewPager.getLimit() == LimitedViewPager.LIMIT_LEFT || !isNext && mViewPager.getLimit() == LimitedViewPager.LIMIT_RIGHT) { mViewPager.setLimit(LimitedViewPager.LIMIT_NONE); } + showToast(R.string.reader_load_success); } + @Override public void initLoad(int progress, int max, String title) { - this.max = max; - mChapterTitle.setText(title); + super.initLoad(progress, max, title); if (progress != 1) { mViewPager.setCurrentItem(PicturePageAdapter.MAX_COUNT / 2 + progress); } else { @@ -203,21 +159,4 @@ public void initLoad(int progress, int max, String title) { } } - public void updateChapterInfo(int count, String title) { - max = count; - mChapterTitle.setText(title); - } - - public void setReadProgress(int progress) { - this.progress = progress; - String text = progress + "/" + max; - mChapterPage.setText(text); - } - - public static Intent createIntent(Context context, Comic comic, List list, int position) { - Intent intent = new Intent(context, PageReaderActivity.class); - putExtras(intent, comic, list, position); - return intent; - } - } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java index f1c43a1b..9b87e2e3 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java @@ -1,42 +1,143 @@ package com.hiroshi.cimoc.ui.activity; +import android.content.Context; import android.content.Intent; -import android.widget.LinearLayout; +import android.view.View; import android.widget.TextView; +import android.widget.Toast; +import com.hiroshi.cimoc.CimocApplication; import com.hiroshi.cimoc.R; import com.hiroshi.cimoc.model.Chapter; import com.hiroshi.cimoc.model.Comic; +import com.hiroshi.cimoc.presenter.BasePresenter; +import com.hiroshi.cimoc.presenter.ReaderPresenter; +import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeViewController.OnSingleTapListener; +import com.hiroshi.cimoc.utils.PreferenceMaster; import org.adw.library.widgets.discreteseekbar.DiscreteSeekBar; +import org.adw.library.widgets.discreteseekbar.DiscreteSeekBar.OnProgressChangeListener; import java.util.List; import butterknife.BindView; +import butterknife.OnClick; /** * Created by Hiroshi on 2016/8/6. */ -public abstract class ReaderActivity extends BaseActivity { +public abstract class ReaderActivity extends BaseActivity implements OnSingleTapListener, OnProgressChangeListener { @BindView(R.id.reader_chapter_title) TextView mChapterTitle; @BindView(R.id.reader_chapter_page) TextView mChapterPage; - @BindView(R.id.reader_tool_bar) LinearLayout mToolLayout; + @BindView(R.id.reader_progress_layout) View mProgressLayout; + @BindView(R.id.reader_back_layout) View mBackLayout; + @BindView(R.id.reader_loading_layout) View mLoadingLayout; @BindView(R.id.reader_seek_bar) DiscreteSeekBar mSeekBar; + protected ReaderPresenter mPresenter; + protected int source; protected int progress; protected int max; + @Override + protected void initView() { + progress = max = 1; + mSeekBar.setOnProgressChangeListener(this); + } + + @Override + protected void onPause() { + super.onPause(); + mPresenter.setPage(progress); + } + + @OnClick(R.id.reader_back_btn) void onBackClick() { + onBackPressed(); + } + @Override protected void initToolbar() {} - protected static final String EXTRA_SOURCE = "a"; - protected static final String EXTRA_CID = "b"; - protected static final String EXTRA_LAST = "c"; - protected static final String EXTRA_PAGE = "d"; - protected static final String EXTRA_TITLE = "e"; - protected static final String EXTRA_PATH = "f"; - protected static final String EXTRA_POSITION = "g"; + @Override + protected BasePresenter getPresenter() { + return mPresenter; + } + + @Override + protected void initPresenter() { + source = getIntent().getIntExtra(EXTRA_SOURCE, -1); + String cid = getIntent().getStringExtra(EXTRA_CID); + String last = getIntent().getStringExtra(EXTRA_LAST); + int page = getIntent().getIntExtra(EXTRA_PAGE, -1); + String[] title = getIntent().getStringArrayExtra(EXTRA_TITLE); + String[] path = getIntent().getStringArrayExtra(EXTRA_PATH); + Chapter[] array = fromArray(title, path); + int position = getIntent().getIntExtra(EXTRA_POSITION, 0); + mPresenter = new ReaderPresenter(this, source, cid, last, page, array, position); + } + + @Override + public void onStartTrackingTouch(DiscreteSeekBar seekBar) {} + + @Override + public void onStopTrackingTouch(DiscreteSeekBar seekBar) {} + + public void updateChapterInfo(int max, String title) { + this.max = max; + mChapterTitle.setText(title); + } + + public void hideToolLayout() { + if (mProgressLayout.isShown()) { + mProgressLayout.setVisibility(View.INVISIBLE); + mBackLayout.setVisibility(View.INVISIBLE); + } + } + + public void switchToolLayout() { + if (mProgressLayout.isShown()) { + mProgressLayout.setVisibility(View.INVISIBLE); + mBackLayout.setVisibility(View.INVISIBLE); + } else { + mSeekBar.setProgress(progress); + mSeekBar.setMax(max); + mProgressLayout.setVisibility(View.VISIBLE); + mBackLayout.setVisibility(View.VISIBLE); + } + } + + public void setReadProgress(int progress) { + this.progress = progress; + String text = progress + "/" + max; + mChapterPage.setText(text); + } + + public void initLoad(int progress, int max, String title) { + mLoadingLayout.setVisibility(View.INVISIBLE); + this.max = max; + mChapterTitle.setText(title); + } + + public void showToast(int resId) { + if (!isFinishing()) { + Toast.makeText(this, resId, Toast.LENGTH_SHORT).show(); + } + } + + public abstract void setPrevImage(String[] array); + + public abstract void setNextImage(String[] array); + + public abstract void loadSuccess(boolean isNext); + + private static final String EXTRA_SOURCE = "a"; + private static final String EXTRA_CID = "b"; + private static final String EXTRA_LAST = "c"; + private static final String EXTRA_PAGE = "d"; + private static final String EXTRA_TITLE = "e"; + private static final String EXTRA_PATH = "f"; + private static final String EXTRA_POSITION = "g"; protected static void putExtras(Intent intent, Comic comic, List list, int position) { intent.putExtra(EXTRA_SOURCE, comic.getSource()); @@ -49,7 +150,7 @@ protected static void putExtras(Intent intent, Comic comic, List list, intent.putExtra(EXTRA_POSITION, position); } - protected static String[][] fromList(List list) { + private static String[][] fromList(List list) { int size = list.size(); String[] title = new String[size]; String[] path = new String[size]; @@ -60,7 +161,7 @@ protected static String[][] fromList(List list) { return new String[][] { title, path }; } - protected static Chapter[] fromArray(String[] title, String[] path) { + private static Chapter[] fromArray(String[] title, String[] path) { int size = title.length; Chapter[] array = new Chapter[size]; for (int i = 0; i != size; ++i) { @@ -69,4 +170,17 @@ protected static Chapter[] fromArray(String[] title, String[] path) { return array; } + + public static Intent createIntent(Context context, Comic comic, List list, int position) { + int mode = CimocApplication.getPreferences().getInt(PreferenceMaster.PREF_MODE, PreferenceMaster.MODE_HORIZONTAL_PAGE); + Intent intent; + if (mode == PreferenceMaster.MODE_HORIZONTAL_PAGE) { + intent = new Intent(context, PageReaderActivity.class); + } else { + intent = new Intent(context, StreamReaderActivity.class); + } + putExtras(intent, comic, list, position); + return intent; + } + } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/ResultActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/ResultActivity.java index c8969665..903773da 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/ResultActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/ResultActivity.java @@ -86,7 +86,7 @@ protected View getLayoutView() { @Override protected String getDefaultTitle() { - return "搜索结果"; + return getString(R.string.result); } @Override @@ -96,9 +96,9 @@ protected BasePresenter getPresenter() { public void addResultSet(List list) { if (list == null) { - showSnackbar("网络错误"); + showSnackbar(R.string.common_network_error); } else if (list.isEmpty() && mResultAdapter.getItemCount() == 0) { - showSnackbar("搜索结果为空"); + showSnackbar(R.string.result_empty); } else { mResultAdapter.addAll(list); } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/StreamReaderActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/StreamReaderActivity.java index 1393dc72..e6a842a3 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/StreamReaderActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/StreamReaderActivity.java @@ -1,34 +1,30 @@ package com.hiroshi.cimoc.ui.activity; -import android.content.Context; -import android.content.Intent; +import android.graphics.Point; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; -import android.util.Log; -import android.view.View; +import com.hiroshi.cimoc.CimocApplication; import com.hiroshi.cimoc.R; -import com.hiroshi.cimoc.model.Chapter; -import com.hiroshi.cimoc.model.Comic; -import com.hiroshi.cimoc.presenter.BasePresenter; -import com.hiroshi.cimoc.presenter.StreamReaderPresenter; import com.hiroshi.cimoc.ui.adapter.PictureStreamAdapter; +import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeView; import com.hiroshi.cimoc.utils.ControllerBuilderFactory; +import com.hiroshi.cimoc.utils.PreferenceMaster; + +import org.adw.library.widgets.discreteseekbar.DiscreteSeekBar; import java.util.Arrays; -import java.util.List; import butterknife.BindView; /** * Created by Hiroshi on 2016/8/5. */ -public class StreamReaderActivity extends ReaderActivity{ +public class StreamReaderActivity extends ReaderActivity { @BindView(R.id.reader_recycler_view) RecyclerView mRecyclerView; private PictureStreamAdapter mStreamAdapter; - private StreamReaderPresenter mPresenter; private LinearLayoutManager mLayoutManager; private int position; @@ -36,56 +32,80 @@ public class StreamReaderActivity extends ReaderActivity{ @Override protected void onPause() { super.onPause(); - mPresenter.setPage(mSeekBar.getProgress()); + mPresenter.setPage(progress); } @Override protected void initView() { - progress = 1; + super.initView(); + position = 0; mLayoutManager = new LinearLayoutManager(this); - mStreamAdapter = new PictureStreamAdapter(this, ControllerBuilderFactory.getControllerBuilder(getIntent().getIntExtra(EXTRA_SOURCE, -1), this)); + mStreamAdapter = new PictureStreamAdapter(this, ControllerBuilderFactory.getControllerBuilder(source, this), this); mRecyclerView.setItemAnimator(null); mRecyclerView.setLayoutManager(mLayoutManager); mRecyclerView.setAdapter(mStreamAdapter); mRecyclerView.addItemDecoration(mStreamAdapter.getItemDecoration()); mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrollStateChanged(RecyclerView recyclerView, int newState) { + switch (newState) { + case RecyclerView.SCROLL_STATE_DRAGGING: + hideToolLayout(); + break; + case RecyclerView.SCROLL_STATE_IDLE: + case RecyclerView.SCROLL_STATE_SETTLING: + int item = mLayoutManager.findLastVisibleItemPosition(); + if (item == mStreamAdapter.getItemCount() - 1) { + mPresenter.loadNext(); + } + break; + } + } + @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { int item = mLayoutManager.findFirstVisibleItemPosition(); if (item != position) { position = item; if (dy > 0) { - ++progress; - if (progress == mSeekBar.getMax()) { - + if (progress == max) { + mPresenter.onChapterToNext(); + } else { + setReadProgress(progress + 1); + } + } else if (dy < 0) { + if (progress == 1) { + mPresenter.onChapterToPrev(); + } else { + setReadProgress(progress - 1); } } else { - --progress; + setReadProgress(progress); } - mPresenter.onScrolled(dy, position, mStreamAdapter.getItemCount()); } - - Log.e("--------------", "-----" + position); } }); } @Override - protected void initPresenter() { - int source = getIntent().getIntExtra(EXTRA_SOURCE, -1); - String cid = getIntent().getStringExtra(EXTRA_CID); - String last = getIntent().getStringExtra(EXTRA_LAST); - int page = getIntent().getIntExtra(EXTRA_PAGE, -1); - String[] title = getIntent().getStringArrayExtra(EXTRA_TITLE); - String[] path = getIntent().getStringArrayExtra(EXTRA_PATH); - Chapter[] array = fromArray(title, path); - int position = getIntent().getIntExtra(EXTRA_POSITION, 0); - mPresenter = new StreamReaderPresenter(this, source, cid, last, page, array, position); + public void onProgressChanged(DiscreteSeekBar seekBar, int value, boolean fromUser) { + if (fromUser) { + int offset = value - progress; + progress = value; + mLayoutManager.scrollToPositionWithOffset(position + offset, 0); + } } @Override - protected BasePresenter getPresenter() { - return mPresenter; + public void onSingleTap(PhotoDraweeView draweeView, float x, float y) { + Point point = new Point(); + getWindowManager().getDefaultDisplay().getSize(point); + float limitY = point.y / 3.0f; + if (position == 0 && draweeView.getId() == 0 && y < limitY) { + mPresenter.loadPrev(); + } else { + switchToolLayout(); + } } @Override @@ -93,36 +113,37 @@ protected int getLayoutRes() { return R.layout.activity_stream_reader; } - public void hideChapterInfo() { - mToolLayout.setVisibility(View.GONE); - mChapterPage.setText(null); - mChapterTitle.setText(null); + @Override + protected boolean isPortrait() { + int mode = CimocApplication.getPreferences().getInt(PreferenceMaster.PREF_MODE, PreferenceMaster.MODE_VERTICAL_STREAM); + return mode == PreferenceMaster.MODE_HORIZONTAL_STREAM; } + @Override public void setPrevImage(String[] array) { mStreamAdapter.addAll(0, Arrays.asList(array)); } + @Override public void setNextImage(String[] array) { mStreamAdapter.addAll(Arrays.asList(array)); } - public void updateChapterInfo(int max, String title) { - mSeekBar.setMax(max); - mChapterTitle.setText(title); - } - - public void setReadProgress(int value) { - mSeekBar.setProgress(value); - String pageString = value + "/" + mSeekBar.getMax(); - mChapterPage.setText(pageString); - progress = value; + @Override + public void loadSuccess(boolean isNext) { + showToast(R.string.reader_load_success); } - public static Intent createIntent(Context context, Comic comic, List list, int position) { - Intent intent = new Intent(context, StreamReaderActivity.class); - putExtras(intent, comic, list, position); - return intent; + @Override + public void initLoad(int progress, int max, String title) { + super.initLoad(progress, max, title); + this.progress = progress; + if (progress != 1) { + mRecyclerView.scrollToPosition(progress - 1); + } else { + String text = progress + "/" + max; + mChapterPage.setText(text); + } } } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ChapterAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ChapterAdapter.java index 6017a159..fb560c39 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ChapterAdapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ChapterAdapter.java @@ -54,7 +54,7 @@ public HeaderHolder(View view) { } } - public ChapterAdapter(Context context, List list, int source, String image, String title, String author, String intro, boolean status, String update) { + public ChapterAdapter(Context context, List list, int source, String image, String title, String author, String intro, boolean status, String update, String last) { super(context, list); this.source = source; this.image = image; @@ -63,6 +63,7 @@ public ChapterAdapter(Context context, List list, int source, String im this.status = status; this.update = update; this.author = author; + this.last = last; } @Override @@ -141,7 +142,7 @@ public int getSpanSize(int position) { } public void setLast(String value) { - if (last == null || value.equals(last)) { + if (value.equals(last)) { last = value; return; } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ComicAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ComicAdapter.java index 45344f26..6a48757d 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ComicAdapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ComicAdapter.java @@ -14,7 +14,6 @@ import com.hiroshi.cimoc.model.MiniComic; import com.hiroshi.cimoc.utils.ControllerBuilderFactory; -import java.util.LinkedList; import java.util.List; import butterknife.BindView; @@ -50,7 +49,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { MiniComic comic = mDataSet.get(position); ViewHolder viewHolder = (ViewHolder) holder; viewHolder.comicTitle.setText(comic.getTitle()); - viewHolder.comicSource.setText(Kami.getSourceById(comic.getSource())); + viewHolder.comicSource.setText(Kami.getSourceTitle(comic.getSource())); PipelineDraweeControllerBuilder builder = ControllerBuilderFactory.getControllerBuilder(comic.getSource(), mContext); viewHolder.comicImage.setController(builder.setUri(comic.getCover()).build()); } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePageAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePageAdapter.java index 5a55db2b..20cc8123 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePageAdapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePageAdapter.java @@ -33,12 +33,12 @@ public class PicturePageAdapter extends PagerAdapter { private int current; - public PicturePageAdapter(List images, LayoutInflater inflater, OnSingleTapListener listener, - PipelineDraweeControllerBuilder builder) { + public PicturePageAdapter(List images, LayoutInflater inflater, PipelineDraweeControllerBuilder builder, + OnSingleTapListener listener) { this.images = images; this.inflater = inflater; - this.listener = listener; this.builder = builder; + this.listener = listener; this.left = MAX_COUNT / 2; this.current = MAX_COUNT / 2 + 1; this.right = MAX_COUNT / 2 + 1; @@ -97,7 +97,6 @@ public void destroyItem(ViewGroup container, int position, Object object) { public Object instantiateItem(ViewGroup container, int position) { View child = inflater.inflate(R.layout.item_picture, container, false); if (left < position && position < right) { - child = inflater.inflate(R.layout.item_picture, container, false); final PhotoDraweeView draweeView = (PhotoDraweeView) child.findViewById(R.id.picture_image_view); draweeView.setScaleType(ImageView.ScaleType.FIT_CENTER); draweeView.setHorizontalMode(); diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PictureStreamAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PictureStreamAdapter.java index e4fdfbb8..49b4a6b1 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PictureStreamAdapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PictureStreamAdapter.java @@ -13,6 +13,7 @@ import com.facebook.imagepipeline.image.ImageInfo; import com.hiroshi.cimoc.R; import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeView; +import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeViewController.OnSingleTapListener; import java.util.LinkedList; @@ -24,10 +25,12 @@ public class PictureStreamAdapter extends BaseAdapter { private PipelineDraweeControllerBuilder builder; + private OnSingleTapListener listener; - public PictureStreamAdapter(Context context, PipelineDraweeControllerBuilder builder) { + public PictureStreamAdapter(Context context, PipelineDraweeControllerBuilder builder, OnSingleTapListener listener) { super(context, new LinkedList()); this.builder = builder; + this.listener = listener; } public class ViewHolder extends BaseViewHolder { @@ -36,6 +39,10 @@ public class ViewHolder extends BaseViewHolder { public ViewHolder(View view) { super(view); } + + public boolean isEquals(PhotoDraweeView draweeView) { + return draweeView == photoView; + } } @Override @@ -47,9 +54,20 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { final PhotoDraweeView draweeView = ((ViewHolder) holder).photoView; + draweeView.setId(position); draweeView.setScaleType(ImageView.ScaleType.CENTER_CROP); draweeView.setVerticalMode(); + draweeView.setOnSingleTapListener(listener); builder.setControllerListener(new BaseControllerListener() { + @Override + public void onIntermediateImageSet(String id, ImageInfo imageInfo) { + super.onIntermediateImageSet(id, imageInfo); + if (imageInfo != null) { + draweeView.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT; + draweeView.setAspectRatio((float) imageInfo.getWidth() / imageInfo.getHeight()); + } + } + @Override public void onFinalImageSet(String id, ImageInfo imageInfo, Animatable animatable) { super.onFinalImageSet(id, imageInfo, animatable); diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ResultAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ResultAdapter.java index d804758f..ccaea3d3 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ResultAdapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ResultAdapter.java @@ -51,7 +51,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { ViewHolder viewHolder = (ViewHolder) holder; viewHolder.comicTitle.setText(comic.getTitle()); viewHolder.comicAuthor.setText(comic.getAuthor()); - viewHolder.comicSource.setText(Kami.getSourceById(comic.getSource())); + viewHolder.comicSource.setText(Kami.getSourceTitle(comic.getSource())); viewHolder.comicUpdate.setText(comic.getUpdate()); PipelineDraweeControllerBuilder builder = ControllerBuilderFactory.getControllerBuilder(comic.getSource(), mContext); viewHolder.comicImage.setController(builder.setUri(comic.getCover()).build()); diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/custom/LimitedViewPager.java b/app/src/main/java/com/hiroshi/cimoc/ui/custom/LimitedViewPager.java index ad568ba5..c3268832 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/custom/LimitedViewPager.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/custom/LimitedViewPager.java @@ -35,28 +35,32 @@ private void init() { @Override public boolean dispatchTouchEvent(MotionEvent ev) { - if (limit == LIMIT_NONE){ - return super.dispatchTouchEvent(ev); - } else if (limit == LIMIT_BOTH) { - return true; - } else { - switch (ev.getAction()) { - case MotionEvent.ACTION_DOWN: - lastX = ev.getX(); - break; - case MotionEvent.ACTION_MOVE: - float value = ev.getX() - lastX; - if (limit == LIMIT_LEFT && value < 0) { - return true; - } - if (limit == LIMIT_RIGHT && value > 0) { - return true; - } - break; + try { + if (limit == LIMIT_NONE){ + return super.dispatchTouchEvent(ev); + } else if (limit == LIMIT_BOTH) { + return true; + } else { + switch (ev.getAction()) { + case MotionEvent.ACTION_DOWN: + lastX = ev.getX(); + break; + case MotionEvent.ACTION_MOVE: + float value = ev.getX() - lastX; + if (limit == LIMIT_LEFT && value < 0) { + return true; + } + if (limit == LIMIT_RIGHT && value > 0) { + return true; + } + break; + } + return super.dispatchTouchEvent(ev); } - return super.dispatchTouchEvent(ev); + } catch (IllegalArgumentException e) { + e.printStackTrace(); } - + return false; } public void nextPage() { diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/PhotoDraweeView.java b/app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/PhotoDraweeView.java index 62fecfc9..215aaaaf 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/PhotoDraweeView.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/PhotoDraweeView.java @@ -6,6 +6,7 @@ import android.util.AttributeSet; import android.view.MotionEvent; +import com.facebook.drawee.controller.AbstractDraweeController; import com.facebook.drawee.generic.GenericDraweeHierarchy; import com.facebook.drawee.view.SimpleDraweeView; @@ -39,6 +40,13 @@ protected void init() { } } + public void retry() { + AbstractDraweeController controller = (AbstractDraweeController) getController(); + if (controller != null) { + controller.onClick(); + } + } + @Override public boolean onTouchEvent(MotionEvent event) { return super.onTouchEvent(event); } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/PhotoDraweeViewController.java b/app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/PhotoDraweeViewController.java index 2904c12d..2f0b78b2 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/PhotoDraweeViewController.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/PhotoDraweeViewController.java @@ -4,7 +4,6 @@ import android.graphics.Matrix; import android.graphics.RectF; import android.os.Build; -import android.support.annotation.Nullable; import android.support.v4.view.GestureDetectorCompat; import android.support.v4.view.MotionEventCompat; import android.support.v4.widget.ScrollerCompat; @@ -30,7 +29,7 @@ public class PhotoDraweeViewController implements OnTouchListener, OnScaleDragGe public static final float MAX_SCALE = 3.0f; public interface OnSingleTapListener { - void onSingleTap(View view, float x, float y); + void onSingleTap(PhotoDraweeView draweeView, float x, float y); } public interface OnScaleChangeListener { @@ -64,12 +63,12 @@ public interface OnScaleChangeListener { private final Matrix mMatrix = new Matrix(); private int mImageInfoHeight = -1, mImageInfoWidth = -1; private FlingRunnable mCurrentFlingRunnable; - private WeakReference> mDraweeView; + private WeakReference mDraweeView; private OnSingleTapListener mSingleTapListener; private OnScaleChangeListener mScaleChangeListener; - public PhotoDraweeViewController(DraweeView draweeView) { + public PhotoDraweeViewController(PhotoDraweeView draweeView) { mDraweeView = new WeakReference<>(draweeView); draweeView.getHierarchy().setActualImageScaleType(ScalingUtils.ScaleType.FIT_CENTER); draweeView.setOnTouchListener(this); @@ -78,7 +77,7 @@ public PhotoDraweeViewController(DraweeView draweeView) mGestureDetector.setOnDoubleTapListener(this); } - @Nullable public DraweeView getDraweeView() { + public PhotoDraweeView getDraweeView() { return mDraweeView.get(); } @@ -322,7 +321,7 @@ private void checkMinScale() { } @Override public boolean onSingleTapConfirmed(MotionEvent e) { - DraweeView draweeView = mDraweeView.get(); + PhotoDraweeView draweeView = mDraweeView.get(); if (draweeView == null) { return false; } @@ -442,17 +441,15 @@ private void checkMinScale() { boolean wasScaling = mScaleDragDetector.isScaling(); boolean wasDragging = mScaleDragDetector.isDragging(); - boolean handled = mScaleDragDetector.onTouchEvent(event); + mScaleDragDetector.onTouchEvent(event); boolean noScale = !wasScaling && !mScaleDragDetector.isScaling(); boolean noDrag = !wasDragging && !mScaleDragDetector.isDragging(); mBlockParentIntercept = noScale && noDrag; - if (mGestureDetector.onTouchEvent(event)) { - handled = true; - } + mGestureDetector.onTouchEvent(event); - return handled; + return true; } private class AnimatedZoomRunnable implements Runnable { diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/BaseFragment.java b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/BaseFragment.java index d28bb432..49b911e3 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/BaseFragment.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/BaseFragment.java @@ -36,6 +36,10 @@ public void onDestroy() { } } + public void showSnackbar(int resId) { + showSnackbar(getString(resId)); + } + public void showSnackbar(String msg) { if (getView() != null) { Snackbar.make(getView(), msg, Snackbar.LENGTH_SHORT).show(); diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/CimocFragment.java b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/CimocFragment.java index e4a34b3b..2bb38428 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/CimocFragment.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/CimocFragment.java @@ -37,7 +37,7 @@ public class CimocFragment extends BaseFragment { @OnClick(R.id.main_search_btn) void onClick() { String keyword = mEditText.getText().toString(); if (keyword.isEmpty()) { - mInputLayout.setError(getString(R.string.empty_for_search)); + mInputLayout.setError(getString(R.string.cimoc_empty_error)); } else { startActivity(ResultActivity.createIntent(getActivity(), keyword, source[choice])); } @@ -80,7 +80,8 @@ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { boolean enable = CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_EX, false); array = enable ? R.array.ex_source_items : R.array.source_items; if (enable) { - source = new int[]{ Kami.SOURCE_IKANMAN, Kami.SOURCE_DMZJ, Kami.SOURCE_HHAAZZ, Kami.SOURCE_CCTUKU, Kami.SOURCE_EHENTAI }; + source = new int[]{ Kami.SOURCE_IKANMAN, Kami.SOURCE_DMZJ, Kami.SOURCE_HHAAZZ, + Kami.SOURCE_CCTUKU, Kami.SOURCE_EXHENTAI, Kami.SOURCE_EHENTAI }; } else { source = new int[]{ Kami.SOURCE_IKANMAN, Kami.SOURCE_DMZJ, Kami.SOURCE_HHAAZZ, Kami.SOURCE_CCTUKU }; } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/FavoriteFragment.java b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/FavoriteFragment.java index 295bc627..1baa6e8e 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/FavoriteFragment.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/FavoriteFragment.java @@ -136,7 +136,7 @@ protected List doInBackground(MiniComic... params) { if (source == Kami.SOURCE_EHENTAI) { continue; } - Manga manga = Kami.getMangaById(source); + Manga manga = Kami.getManga(source); String update = manga.check(comic.getCid()); if (update != null && !comic.getUpdate().equals(update)) { comic.setUpdate(update); diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SettingsFragment.java b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SettingsFragment.java index c3b9c2fd..0874da1f 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SettingsFragment.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SettingsFragment.java @@ -10,6 +10,7 @@ import com.hiroshi.cimoc.R; import com.hiroshi.cimoc.presenter.BasePresenter; import com.hiroshi.cimoc.presenter.SettingsPresenter; +import com.hiroshi.cimoc.ui.activity.BaseActivity; import com.hiroshi.cimoc.utils.DialogFactory; import com.hiroshi.cimoc.utils.PreferenceMaster; @@ -24,6 +25,7 @@ public class SettingsFragment extends BaseFragment { @BindView(R.id.settings_other_home_summary) TextView mHomeSummary; @BindView(R.id.settings_reader_mode_summary) TextView mModeSummary; @BindView(R.id.settings_reader_volume_checkbox) CheckBox mVolumeBox; + @BindView(R.id.settings_other_nightly_checkbox) CheckBox mNightlyBox; private SettingsPresenter mPresenter; private PreferenceMaster mPreference; @@ -34,6 +36,7 @@ public class SettingsFragment extends BaseFragment { private int mModeChoice; private int mTempChoice; private boolean mVolumeChoice; + private boolean mNightlyChoice; private OnClickListener mSingleChoiceListener = new OnClickListener() { @Override @@ -49,9 +52,22 @@ protected void initView() { mHomeChoice = mPreference.getInt(PreferenceMaster.PREF_HOME, PreferenceMaster.HOME_CIMOC); mModeChoice = mPreference.getInt(PreferenceMaster.PREF_MODE, PreferenceMaster.MODE_HORIZONTAL_PAGE); mVolumeChoice = mPreference.getBoolean(PreferenceMaster.PREF_VOLUME, false); + mNightlyChoice = mPreference.getBoolean(PreferenceMaster.PREF_NIGHTLY, false); mHomeSummary.setText(getResources().getStringArray(R.array.home_items)[mHomeChoice]); mModeSummary.setText(getResources().getStringArray(R.array.mode_items)[mModeChoice]); mVolumeBox.setChecked(mVolumeChoice); + mNightlyBox.setChecked(mNightlyChoice); + } + + @OnClick(R.id.settings_other_nightly_btn) void onNightlyBtnClick() { + mNightlyChoice = !mNightlyChoice; + mNightlyBox.setChecked(mNightlyChoice); + if (mNightlyChoice) { + ((BaseActivity) getActivity()).nightlyOn(); + } else { + ((BaseActivity) getActivity()).nightlyOff(); + } + mPreference.putBoolean(PreferenceMaster.PREF_NIGHTLY, mNightlyChoice); } @OnClick(R.id.settings_reader_volume_btn) void onVolumeBtnClick() { @@ -63,7 +79,7 @@ protected void initView() { @OnClick(R.id.settings_backup_restore_btn) void onRestoreBtnClick() { final String[] array = mPresenter.getFiles(); if (array == null) { - showSnackbar("没有找到备份文件"); + showSnackbar(R.string.settings_backup_save_not_found); return; } DialogFactory.buildSingleChoiceDialog(getActivity(), R.string.settings_select_file, array, -1, mSingleChoiceListener, @@ -95,7 +111,7 @@ public void onClick(DialogInterface dialog, int which) { @Override public void onClick(DialogInterface dialog, int which) { mModeChoice = mTempChoice; - mPreference.putInt(PreferenceMaster.PREF_HOME, mModeChoice); + mPreference.putInt(PreferenceMaster.PREF_MODE, mModeChoice); mModeSummary.setText(getResources().getStringArray(R.array.mode_items)[mModeChoice]); } }).show(); @@ -124,8 +140,8 @@ protected int getLayoutView() { return R.layout.fragment_settings; } - public void showProgressDialog(String msg) { - mProgressDialog.setMessage(msg); + public void showProgressDialog(int resId) { + mProgressDialog.setMessage(getString(resId)); mProgressDialog.show(); } diff --git a/app/src/main/java/com/hiroshi/cimoc/utils/ControllerBuilderFactory.java b/app/src/main/java/com/hiroshi/cimoc/utils/ControllerBuilderFactory.java index 187bb733..45c67285 100644 --- a/app/src/main/java/com/hiroshi/cimoc/utils/ControllerBuilderFactory.java +++ b/app/src/main/java/com/hiroshi/cimoc/utils/ControllerBuilderFactory.java @@ -42,7 +42,7 @@ private static ImagePipelineFactory buildFactory(Context context, final int sour OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { - String referer = Kami.getRefererById(source); + String referer = Kami.getReferer(source); Request.Builder request = chain.request().newBuilder(); request.addHeader("Referer", referer); if (cookie != null) { diff --git a/app/src/main/java/com/hiroshi/cimoc/utils/ExLog.java b/app/src/main/java/com/hiroshi/cimoc/utils/ExLog.java index 58691e79..f66fbe7c 100644 --- a/app/src/main/java/com/hiroshi/cimoc/utils/ExLog.java +++ b/app/src/main/java/com/hiroshi/cimoc/utils/ExLog.java @@ -7,7 +7,7 @@ */ public class ExLog { - private static boolean DEBUG = true; + private static boolean DEBUG = false; public static void d(String tag, String msg) { if (DEBUG) { diff --git a/app/src/main/java/com/hiroshi/cimoc/utils/PreferenceMaster.java b/app/src/main/java/com/hiroshi/cimoc/utils/PreferenceMaster.java index 1884a743..276b6c33 100644 --- a/app/src/main/java/com/hiroshi/cimoc/utils/PreferenceMaster.java +++ b/app/src/main/java/com/hiroshi/cimoc/utils/PreferenceMaster.java @@ -22,6 +22,7 @@ public class PreferenceMaster { public static final String PREF_HOME = "pref_home"; public static final String PREF_MODE = "pref_mode"; public static final String PREF_VOLUME = "pref_volume"; + public static final String PREF_NIGHTLY = "pref_nightly"; private static final String PREFERENCES_NAME = "cimoc_preferences"; diff --git a/app/src/main/res/drawable-hdpi/ic_navigate_before_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_navigate_before_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..bd23a06968e3d17c8b3a44680e59428841de752b GIT binary patch literal 132 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B5}8r;B5V$MLsUPI59R2sj5iURcJu zTy^?CB{^H^0>%9ebP0l+XkKZbLLy literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_navigate_before_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_navigate_before_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..87a5f5196302b9f30a9d7984516861666dee2c10 GIT binary patch literal 202 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhawCVIL!hGg7(dt*CqgM$F;MePQr z4Re#$dDrN2r*JTGGX3*37TuH6TkHY?^6B^Xh^3#-E)4Oo?qhm+z%X0)(xW3@bNqTI zYZO+Q`mH)5`QT20+vx`}MQW!X#uTM#Kj3ISq~P1NL?)k - + + - - - + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_stream_reader.xml b/app/src/main/res/layout/activity_stream_reader.xml index d80f9d0f..0a17fb3f 100644 --- a/app/src/main/res/layout/activity_stream_reader.xml +++ b/app/src/main/res/layout/activity_stream_reader.xml @@ -1,9 +1,9 @@ + - - - + + \ No newline at end of file diff --git a/app/src/main/res/layout/custom_back_btn.xml b/app/src/main/res/layout/custom_back_btn.xml new file mode 100644 index 00000000..5cfc98b0 --- /dev/null +++ b/app/src/main/res/layout/custom_back_btn.xml @@ -0,0 +1,18 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_picture_msg.xml b/app/src/main/res/layout/custom_loading.xml similarity index 78% rename from app/src/main/res/layout/item_picture_msg.xml rename to app/src/main/res/layout/custom_loading.xml index 99019aa4..31c6ebd2 100644 --- a/app/src/main/res/layout/item_picture_msg.xml +++ b/app/src/main/res/layout/custom_loading.xml @@ -1,13 +1,14 @@ - \ No newline at end of file + diff --git a/app/src/main/res/layout/custom_seek_bar.xml b/app/src/main/res/layout/custom_seek_bar.xml new file mode 100644 index 00000000..493fb443 --- /dev/null +++ b/app/src/main/res/layout/custom_seek_bar.xml @@ -0,0 +1,26 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_about.xml b/app/src/main/res/layout/fragment_about.xml index 38605906..58a0c8ab 100644 --- a/app/src/main/res/layout/fragment_about.xml +++ b/app/src/main/res/layout/fragment_about.xml @@ -50,4 +50,32 @@ android:textSize="14sp" android:text="@string/about_resource_url"/> + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_cimoc.xml b/app/src/main/res/layout/fragment_cimoc.xml index 27c6fad3..7bc0b157 100644 --- a/app/src/main/res/layout/fragment_cimoc.xml +++ b/app/src/main/res/layout/fragment_cimoc.xml @@ -21,7 +21,7 @@ android:layout_marginLeft="20dp" android:layout_marginRight="20dp" android:layout_gravity="top" - android:hint="@string/hint_for_search" + android:hint="@string/cimoc_search_hint" android:textColorHint="@color/white" app:counterEnabled="true" app:theme="@style/TextInputTheme"> diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml index f2589fb4..633eb3bd 100644 --- a/app/src/main/res/layout/fragment_settings.xml +++ b/app/src/main/res/layout/fragment_settings.xml @@ -155,6 +155,39 @@ android:textColor="?attr/colorAccent" android:textSize="14sp" android:text="@string/settings_other"/> + + + + + diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 829657f8..4838b247 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -12,6 +12,7 @@ 汗汗漫画 - HHAAZZ CC图库 - CCTuku Ex绅士 - ExHentai + E绅士 - EHentai Cimoc diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index f4e9efaa..2ee41fb3 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -12,6 +12,7 @@ #AAFFC107 #4F000000 - #AABEBEBE - #CC000000 + #AA7F7F80 + #AABEBEBE + #AA000000 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 01e4cad3..18048ee0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -9,51 +9,80 @@ 设置 关于 - 请输入漫画名 - 关键字不能为空 + 请输入漫画名 + 关键字不能为空 + 图源选择 + 搜索结果 最后更新: 来源: + 搜索结果为空 + 详情 最后更新: - 获取详情失败 :( - - 前面没有了 :( - - 图源选择 + 解析错误或此漫画已被屏蔽 + 收藏成功 + 取消收藏成功 是否删除该漫画 是否检查更新 + NEW 是否删除该历史纪录 是否清除所有历史纪录 - NEW - - version: 1.1.0 + 前面没有了 + 后面没有了 + 正在加载上一话 + 正在加载下一话 + 加载错误 + 加载成功 + 正在加载中.. 备份设置 备份 备份到本地文件 + 备份成功 数量为 + 备份失败 + 没有找到备份文件 + 正在备份.. 恢复 从本地文件中恢复 + 恢复成功 数量为 + 正在恢复.. 阅读设置 阅读模式 音量键翻页 仅限翻页模式 其他设置 + 夜间模式 + 全局夜间模式 首页设置 清除缓存 - + 正在清除.. + 清除成功 首页选择 阅读模式选择 文件选择 + version: 1.1.0 源代码 https://github.com/Arachnid-27/Cimoc + 支持作者 + 如果喜欢本应用,不妨支持一下作者哟 + 支付宝账号:cimoc_app@163.com 操作确认 确定 取消 + 看漫画 + 动漫之家 + 汗汗漫画 + CC图库 + E-Hentai + ExHentai + + 网络错误 + From c12521a6dcfe8db3617e036e6395deceb087792c Mon Sep 17 00:00:00 2001 From: hiroshi Date: Mon, 8 Aug 2016 13:52:25 +0800 Subject: [PATCH 006/521] =?UTF-8?q?=E5=8A=A0=E5=85=A5=E6=9C=89=E5=A6=96?= =?UTF-8?q?=E6=B0=94=20=E6=9B=B4=E6=96=B0README.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 11 +- .../java/com/hiroshi/cimoc/core/CCTuku.java | 6 +- .../java/com/hiroshi/cimoc/core/Dmzj.java | 2 +- .../java/com/hiroshi/cimoc/core/EHentai.java | 2 +- .../java/com/hiroshi/cimoc/core/ExHentai.java | 4 +- .../java/com/hiroshi/cimoc/core/HHAAZZ.java | 2 +- .../java/com/hiroshi/cimoc/core/IKanman.java | 4 +- .../java/com/hiroshi/cimoc/core/Kami.java | 12 +- .../main/java/com/hiroshi/cimoc/core/U17.java | 109 ++++++++++++++++++ .../com/hiroshi/cimoc/core/base/Manga.java | 6 +- .../cimoc/ui/activity/BaseActivity.java | 21 ++-- .../cimoc/ui/activity/MainActivity.java | 8 ++ .../cimoc/ui/activity/PageReaderActivity.java | 7 +- .../cimoc/ui/activity/ReaderActivity.java | 10 ++ .../ui/activity/StreamReaderActivity.java | 4 +- .../cimoc/ui/adapter/ComicAdapter.java | 3 +- .../cimoc/ui/adapter/PicturePageAdapter.java | 4 + .../ui/custom/photo/PhotoDraweeView.java | 6 +- .../cimoc/ui/fragment/AboutFragment.java | 15 ++- .../cimoc/ui/fragment/CimocFragment.java | 8 +- .../cimoc/ui/fragment/SettingsFragment.java | 6 +- .../com/hiroshi/cimoc/utils/Decryption.java | 7 +- .../com/hiroshi/cimoc/utils/MachiSoup.java | 41 +++++-- app/src/main/res/drawable/flag_comic_new.xml | 14 +++ app/src/main/res/layout/custom_back_btn.xml | 2 +- app/src/main/res/layout/custom_toolbar.xml | 4 +- app/src/main/res/layout/fragment_about.xml | 6 + app/src/main/res/layout/item_comic.xml | 9 +- app/src/main/res/values/arrays.xml | 13 ++- app/src/main/res/values/colors.xml | 1 + app/src/main/res/values/strings.xml | 7 +- 31 files changed, 282 insertions(+), 72 deletions(-) create mode 100644 app/src/main/java/com/hiroshi/cimoc/core/U17.java create mode 100644 app/src/main/res/drawable/flag_comic_new.xml diff --git a/README.md b/README.md index f4768cd9..eedb54e6 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,22 @@ # 应用简介 -Android 平台在线看漫画的应用 +Android 平台在线漫画阅读器 + +# 功能简介 +- 翻页阅读 +- 卷纸阅读 +- 夜间模式 +- 检查更新 +- 本地备份恢复 # 支持网站 - [看漫画](http://m.ikanman.com) - [动漫之家](http://m.dmzj.com) - [汗汗漫画](http://hhaazz.com) - [CC图库](http://m.tuku.cc) +- [有妖气](http://www.u17.com) - ~~E绅士~~ +- ~~Ex绅士~~ # 应用截图 diff --git a/app/src/main/java/com/hiroshi/cimoc/core/CCTuku.java b/app/src/main/java/com/hiroshi/cimoc/core/CCTuku.java index daec375d..7fe919de 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/CCTuku.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/CCTuku.java @@ -29,8 +29,12 @@ protected Request buildSearchRequest(String keyword, int page) { } @Override - protected List parseSearch(String html) { + protected List parseSearch(String html, int page) { Node body = MachiSoup.body(html); + int total = Integer.parseInt(MachiSoup.match("\\d+", body.text("div.title-banner > div > h1"), 0)); + if (page > total) { + return null; + } List list = new LinkedList<>(); for (Node node : body.list(".main-list > div > div > div")) { String cid = node.attr("div:eq(1) > div:eq(0) > a", "href", "/", 2); diff --git a/app/src/main/java/com/hiroshi/cimoc/core/Dmzj.java b/app/src/main/java/com/hiroshi/cimoc/core/Dmzj.java index cb7541c7..592127dd 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/Dmzj.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/Dmzj.java @@ -35,7 +35,7 @@ protected Request buildSearchRequest(String keyword, int page) { } @Override - protected List parseSearch(String html) { + protected List parseSearch(String html, int page) { String jsonString = MachiSoup.match("g_search_data = (.*);", html, 1); List list = new LinkedList<>(); if (jsonString != null) { diff --git a/app/src/main/java/com/hiroshi/cimoc/core/EHentai.java b/app/src/main/java/com/hiroshi/cimoc/core/EHentai.java index 38e8594e..e408fb42 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/EHentai.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/EHentai.java @@ -27,7 +27,7 @@ protected Request buildSearchRequest(String keyword, int page) { } @Override - protected List parseSearch(String html) { + protected List parseSearch(String html, int page) { Node body = MachiSoup.body(html); List nodes = body.list("#ig > div > table > tbody > tr"); List list = new LinkedList<>(); diff --git a/app/src/main/java/com/hiroshi/cimoc/core/ExHentai.java b/app/src/main/java/com/hiroshi/cimoc/core/ExHentai.java index 7dd464ad..d43bdcd8 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/ExHentai.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/ExHentai.java @@ -17,7 +17,7 @@ public class ExHentai extends Manga { public ExHentai() { - super(Kami.SOURCE_EHENTAI, "https://exhentai.org"); + super(Kami.SOURCE_EXHENTAI, "https://exhentai.org"); } @Override @@ -27,7 +27,7 @@ protected Request buildSearchRequest(String keyword, int page) { } @Override - protected List parseSearch(String html) { + protected List parseSearch(String html, int page) { Node body = MachiSoup.body(html); List list = new LinkedList<>(); for (Node node : body.list("table.itg > tbody > tr[class^=gtr]")) { diff --git a/app/src/main/java/com/hiroshi/cimoc/core/HHAAZZ.java b/app/src/main/java/com/hiroshi/cimoc/core/HHAAZZ.java index 923e6d3c..70a65a40 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/HHAAZZ.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/HHAAZZ.java @@ -31,7 +31,7 @@ protected Request buildSearchRequest(String keyword, int page) { } @Override - protected List parseSearch(String html) { + protected List parseSearch(String html, int page) { Node body = MachiSoup.body(html); List nodes = body.list(".se-list > li"); List list = new LinkedList<>(); diff --git a/app/src/main/java/com/hiroshi/cimoc/core/IKanman.java b/app/src/main/java/com/hiroshi/cimoc/core/IKanman.java index d2bedc60..c0c72e4b 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/IKanman.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/IKanman.java @@ -31,7 +31,7 @@ protected Request buildSearchRequest(String keyword, int page) { } @Override - protected List parseSearch(String html) { + protected List parseSearch(String html, int page) { Node body = MachiSoup.body(html); List list = new LinkedList<>(); for (Node node : body.list("#detail > li > a")) { @@ -95,7 +95,7 @@ protected String[] parseBrowse(String html) { JSONObject info = new JSONObject(jsonString); JSONArray array = info.getJSONArray("images"); String[] images = new String[array.length()]; - for (int i = 0; i != array.length(); ++i) { + for (int i = 0; i != images.length; ++i) { images[i] = "http://i.hamreus.com:8080" + array.getString(i); } return images; diff --git a/app/src/main/java/com/hiroshi/cimoc/core/Kami.java b/app/src/main/java/com/hiroshi/cimoc/core/Kami.java index e075223e..ccfc5853 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/Kami.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/Kami.java @@ -12,6 +12,7 @@ public class Kami { public static final int SOURCE_DMZJ = 1; public static final int SOURCE_HHAAZZ = 2; public static final int SOURCE_CCTUKU = 3; + public static final int SOURCE_U17 = 4; public static final int SOURCE_EHENTAI = 100; public static final int SOURCE_EXHENTAI = 101; @@ -26,6 +27,8 @@ public static int getSourceTitle(int id) { return R.string.source_hhaazz; case SOURCE_CCTUKU: return R.string.source_cctuku; + case SOURCE_U17: + return R.string.source_u17; case SOURCE_EHENTAI: return R.string.source_ehentai; case SOURCE_EXHENTAI: @@ -44,6 +47,8 @@ public static String getReferer(int id) { return "http://hhaazz.com"; case SOURCE_CCTUKU: return "http://m.tuku.cc"; + case SOURCE_U17: + return "http://www.u17.com"; case SOURCE_EHENTAI: return "http://lofi.e-hentai.org"; case SOURCE_EXHENTAI: @@ -51,7 +56,7 @@ public static String getReferer(int id) { } } - private static Manga mIkanman, mDmzj, mHHAAZZ, mCCTuku, mExHentai, mEHentai; + private static Manga mIkanman, mDmzj, mHHAAZZ, mCCTuku, mU17, mExHentai, mEHentai; public static Manga getManga(int id) { switch (id) { @@ -76,6 +81,11 @@ public static Manga getManga(int id) { mCCTuku = new CCTuku(); } return mCCTuku; + case SOURCE_U17: + if (mU17 == null) { + mU17 = new U17(); + } + return mU17; case SOURCE_EHENTAI: if (mEHentai == null) { mEHentai = new EHentai(); diff --git a/app/src/main/java/com/hiroshi/cimoc/core/U17.java b/app/src/main/java/com/hiroshi/cimoc/core/U17.java new file mode 100644 index 00000000..a858dcee --- /dev/null +++ b/app/src/main/java/com/hiroshi/cimoc/core/U17.java @@ -0,0 +1,109 @@ +package com.hiroshi.cimoc.core; + +import com.hiroshi.cimoc.core.base.Manga; +import com.hiroshi.cimoc.model.Chapter; +import com.hiroshi.cimoc.model.Comic; +import com.hiroshi.cimoc.utils.Decryption; +import com.hiroshi.cimoc.utils.MachiSoup; +import com.hiroshi.cimoc.utils.MachiSoup.Node; + +import java.util.LinkedList; +import java.util.List; + +import okhttp3.Request; + +/** + * Created by Hiroshi on 2016/8/8. + */ +public class U17 extends Manga { + + public U17() { + super(Kami.SOURCE_U17, "http://www.u17.com"); + } + + @Override + protected Request buildSearchRequest(String keyword, int page) { + String url = "http://so.u17.com/all/" + keyword + "/m0_p" + page + ".html"; + return new Request.Builder().url(url).build(); + } + + @Override + protected List parseSearch(String html, int page) { + MachiSoup.Node body = MachiSoup.body(html); + List list = new LinkedList<>(); + for (MachiSoup.Node node : body.list(".comiclist > ul > li > div")) { + String cid = node.attr("div:eq(1) > h3 > strong > a", "href", "/|\\.", 6); + String title = node.attr("div:eq(1) > h3 > strong > a", "title"); + String cover = node.attr("div:eq(0) > a > img", "src"); + String update = node.text("div:eq(1) > h3 > span.fr", 7); + String author = node.text("div:eq(1) > h3 > a[title]"); + String[] array = node.text("div:eq(1) > p.cf > i.fl").split("/"); + boolean status = "已完结".equals(array[array.length - 1].trim()); + list.add(new Comic(source, cid, title, cover, update, author, status)); + } + return list; + } + + @Override + protected Request buildIntoRequest(String cid) { + String url = host + "/comic/" + cid + ".html"; + return new Request.Builder().url(url).build(); + } + + @Override + protected List parseInto(String html, Comic comic) { + List list = new LinkedList<>(); + MachiSoup.Node body = MachiSoup.body(html); + for (MachiSoup.Node node : body.list("#chapter > li > a")) { + String c_title = node.text().trim(); + String c_path = node.attr("href", "/|\\.", 6); + list.add(0, new Chapter(c_title, c_path)); + } + + Node detail = body.select("div.comic_info"); + String title = body.text("div:eq(0) > h1").trim(); + String cover = detail.attr("div:eq(0) > div.coverBox > div.cover > a > img", "src"); + String author = detail.text("div:eq(1) > div > div.info > a:eq(0)"); + String intro = detail.text("div:eq(0) > div.info > #words").trim(); + boolean status = "已完结".equals(body.text("div.main > div.info > div.fl > span.eq(2)")); + String update = body.text("div.main > div.chapterlist > div.chapterlist_box > div.bot > div:eq(0) > span", 7); + comic.setInfo(title, cover, update, intro, author, status); + return list; + } + + @Override + protected Request buildBrowseRequest(String cid, String path) { + String url = host + "/chapter/" + path + ".html"; + return new Request.Builder().url(url).build(); + } + + @Override + protected String[] parseBrowse(String html) { + List list = MachiSoup.matchAll("\"src\":\"(.*?)\"", html, 1); + if (!list.isEmpty()) { + try { + String[] images = new String[list.size()]; + for (int i = 0; i != images.length; ++i) { + images[i] = Decryption.base64Decrypt(list.get(i)); + } + return images; + } catch (Exception e) { + e.printStackTrace(); + } + } + return null; + } + + @Override + protected Request buildCheckRequest(String cid) { + String url = host + "/comic/" + cid + ".html"; + return new Request.Builder().url(url).build(); + } + + @Override + protected String parseCheck(String html) { + MachiSoup.Node body = MachiSoup.body(html); + return body.text("div.main > div.chapterlist > div.chapterlist_box > div.bot > div:eq(0) > span", 7); + } + +} diff --git a/app/src/main/java/com/hiroshi/cimoc/core/base/Manga.java b/app/src/main/java/com/hiroshi/cimoc/core/base/Manga.java index 01e1fa4d..142ec18d 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/base/Manga.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/base/Manga.java @@ -33,7 +33,7 @@ public Manga(int source, String host) { this.mClient = CimocApplication.getHttpClient(); } - public void search(String keyword, int page) { + public void search(String keyword, final int page) { Request request = buildSearchRequest(keyword, page); if (request == null) { EventBus.getDefault().post(new EventMessage(EventMessage.SEARCH_FAIL, null)); @@ -41,7 +41,7 @@ public void search(String keyword, int page) { enqueueClient(request, new OnResponseSuccessHandler() { @Override public void onSuccess(String html) { - List list = parseSearch(html); + List list = parseSearch(html, page); if (list == null || list.isEmpty()) { EventBus.getDefault().post(new EventMessage(EventMessage.SEARCH_FAIL, null)); } else { @@ -132,7 +132,7 @@ protected String execute(Request request) { protected abstract Request buildSearchRequest(String keyword, int page); - protected abstract List parseSearch(String html); + protected abstract List parseSearch(String html, int page); protected abstract Request buildIntoRequest(String cid); diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/BaseActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/BaseActivity.java index e249deb7..54af1c61 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/BaseActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/BaseActivity.java @@ -9,7 +9,6 @@ import android.support.v7.widget.Toolbar; import android.view.View; import android.view.WindowManager; -import android.widget.FrameLayout; import com.hiroshi.cimoc.CimocApplication; import com.hiroshi.cimoc.R; @@ -23,8 +22,7 @@ */ public abstract class BaseActivity extends AppCompatActivity { - private View nightlyView; - + protected View maskView; protected Toolbar mToolbar; @Override @@ -49,17 +47,18 @@ protected void onCreate(Bundle savedInstanceState) { @Override protected void onDestroy() { super.onDestroy(); + ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).removeViewImmediate(maskView); if (getPresenter() != null) { getPresenter().onDestroy(); } } private void initNightly() { - nightlyView = new FrameLayout(this); - nightlyView.setBackgroundColor(getResources().getColor(R.color.trans_black)); + maskView = new View(this); + ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).addView(maskView, getParams()); boolean nightly = CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_NIGHTLY, false); if (nightly) { - nightlyOn(); + maskView.setBackgroundColor(getResources().getColor(R.color.trans_black)); } } @@ -72,17 +71,11 @@ protected void initToolbar() { } } - public void nightlyOn() { - WindowManager.LayoutParams params = new WindowManager.LayoutParams( - WindowManager.LayoutParams.MATCH_PARENT,WindowManager.LayoutParams.MATCH_PARENT, + protected WindowManager.LayoutParams getParams() { + return new WindowManager.LayoutParams( WindowManager.LayoutParams.TYPE_APPLICATION, WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT); - ((WindowManager)getSystemService(Context.WINDOW_SERVICE)).addView(nightlyView, params); - } - - public void nightlyOff() { - ((WindowManager)getSystemService(Context.WINDOW_SERVICE)).removeView(nightlyView); } protected View getLayoutView() { diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/MainActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/MainActivity.java index fab9e9c8..ac82c731 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/MainActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/MainActivity.java @@ -106,6 +106,14 @@ public void setCheckedItem(int id) { mNavigationView.setCheckedItem(id); } + public void nightlyOn() { + maskView.setBackgroundColor(getResources().getColor(R.color.trans_black)); + } + + public void nightlyOff() { + maskView.setBackgroundColor(getResources().getColor(R.color.trans_white)); + } + public void showProgressBar() { mFrameLayout.setVisibility(View.GONE); mProgressBar.setVisibility(View.VISIBLE); diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/PageReaderActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/PageReaderActivity.java index 50550495..713ce8c1 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/PageReaderActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/PageReaderActivity.java @@ -153,7 +153,12 @@ public void initLoad(int progress, int max, String title) { if (progress != 1) { mViewPager.setCurrentItem(PicturePageAdapter.MAX_COUNT / 2 + progress); } else { - mViewPager.setLimit(LimitedViewPager.LIMIT_RIGHT); + if (mPageAdapter.isToBoth()) { + mViewPager.setLimit(LimitedViewPager.LIMIT_BOTH); + mPresenter.loadNext(); + } else { + mViewPager.setLimit(LimitedViewPager.LIMIT_RIGHT); + } String text = progress + "/" + max; mChapterPage.setText(text); } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java index 9b87e2e3..7d6afa85 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java @@ -2,7 +2,9 @@ import android.content.Context; import android.content.Intent; +import android.graphics.PixelFormat; import android.view.View; +import android.view.WindowManager; import android.widget.TextView; import android.widget.Toast; @@ -59,6 +61,14 @@ protected void onPause() { @Override protected void initToolbar() {} + @Override + protected WindowManager.LayoutParams getParams() { + return new WindowManager.LayoutParams( + WindowManager.LayoutParams.TYPE_APPLICATION, + WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_FULLSCREEN, + PixelFormat.TRANSLUCENT); + } + @Override protected BasePresenter getPresenter() { return mPresenter; diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/StreamReaderActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/StreamReaderActivity.java index e6a842a3..ff73caa2 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/StreamReaderActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/StreamReaderActivity.java @@ -101,9 +101,9 @@ public void onSingleTap(PhotoDraweeView draweeView, float x, float y) { Point point = new Point(); getWindowManager().getDefaultDisplay().getSize(point); float limitY = point.y / 3.0f; - if (position == 0 && draweeView.getId() == 0 && y < limitY) { + if (mRecyclerView.getChildAdapterPosition(draweeView) == 0 && y < limitY) { mPresenter.loadPrev(); - } else { + } else if (!draweeView.retry()) { switchToolLayout(); } } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ComicAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ComicAdapter.java index 6a48757d..7f5b67ed 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ComicAdapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ComicAdapter.java @@ -5,6 +5,7 @@ import android.support.v7.widget.RecyclerView; import android.view.View; import android.view.ViewGroup; +import android.widget.ImageView; import android.widget.TextView; import com.facebook.drawee.backends.pipeline.PipelineDraweeControllerBuilder; @@ -27,7 +28,7 @@ public class ViewHolder extends BaseViewHolder { @BindView(R.id.item_comic_image) SimpleDraweeView comicImage; @BindView(R.id.item_comic_title) TextView comicTitle; @BindView(R.id.item_comic_source) TextView comicSource; - @BindView(R.id.item_comic_new) TextView comicNew; + @BindView(R.id.item_comic_new) ImageView comicNew; public ViewHolder(View view) { super(view); diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePageAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePageAdapter.java index 20cc8123..116841b0 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePageAdapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePageAdapter.java @@ -64,6 +64,10 @@ public void setNextImages(String[] array) { notifyDataSetChanged(); } + public boolean isToBoth() { + return isToLeft() && isToRight(); + } + public boolean isToLeft() { return current == left + 1; } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/PhotoDraweeView.java b/app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/PhotoDraweeView.java index 215aaaaf..dea5ddb5 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/PhotoDraweeView.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/custom/photo/PhotoDraweeView.java @@ -40,11 +40,9 @@ protected void init() { } } - public void retry() { + public boolean retry() { AbstractDraweeController controller = (AbstractDraweeController) getController(); - if (controller != null) { - controller.onClick(); - } + return controller != null && controller.onClick(); } @Override public boolean onTouchEvent(MotionEvent event) { diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/AboutFragment.java b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/AboutFragment.java index 65c5ae1c..33c2d815 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/AboutFragment.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/AboutFragment.java @@ -1,8 +1,11 @@ package com.hiroshi.cimoc.ui.fragment; +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; + import com.hiroshi.cimoc.CimocApplication; import com.hiroshi.cimoc.R; -import com.hiroshi.cimoc.presenter.BasePresenter; import com.hiroshi.cimoc.utils.PreferenceMaster; import butterknife.OnClick; @@ -15,11 +18,17 @@ public class AboutFragment extends BaseFragment { private boolean isEnable; private int count; - @OnClick(R.id.about_resource_btn) void onClick() { + @OnClick(R.id.about_support_btn) void onSupportClick() { + ClipboardManager manager = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE); + manager.setPrimaryClip(ClipData.newPlainText(null, getString(R.string.about_support_email))); + showSnackbar(R.string.about_already_clip); + } + + @OnClick(R.id.about_resource_btn) void onResourceClick() { if (++count > 9) { isEnable = !isEnable; CimocApplication.getPreferences().putBoolean(PreferenceMaster.PREF_EX, isEnable); - showSnackbar(isEnable ? "重启软件开启 EHentai" : "重启软件关闭 EHentai"); + showSnackbar(isEnable ? R.string.about_turn_on : R.string.about_turn_off); count = 0; } } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/CimocFragment.java b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/CimocFragment.java index 2bb38428..a8afd571 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/CimocFragment.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/CimocFragment.java @@ -12,7 +12,6 @@ import com.hiroshi.cimoc.CimocApplication; import com.hiroshi.cimoc.R; -import com.hiroshi.cimoc.core.Kami; import com.hiroshi.cimoc.ui.activity.ResultActivity; import com.hiroshi.cimoc.utils.DialogFactory; import com.hiroshi.cimoc.utils.PreferenceMaster; @@ -79,12 +78,7 @@ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { choice = 0; boolean enable = CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_EX, false); array = enable ? R.array.ex_source_items : R.array.source_items; - if (enable) { - source = new int[]{ Kami.SOURCE_IKANMAN, Kami.SOURCE_DMZJ, Kami.SOURCE_HHAAZZ, - Kami.SOURCE_CCTUKU, Kami.SOURCE_EXHENTAI, Kami.SOURCE_EHENTAI }; - } else { - source = new int[]{ Kami.SOURCE_IKANMAN, Kami.SOURCE_DMZJ, Kami.SOURCE_HHAAZZ, Kami.SOURCE_CCTUKU }; - } + source = getResources().getIntArray(R.array.source_id_items); } @Override diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SettingsFragment.java b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SettingsFragment.java index 0874da1f..221119cb 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SettingsFragment.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SettingsFragment.java @@ -10,7 +10,7 @@ import com.hiroshi.cimoc.R; import com.hiroshi.cimoc.presenter.BasePresenter; import com.hiroshi.cimoc.presenter.SettingsPresenter; -import com.hiroshi.cimoc.ui.activity.BaseActivity; +import com.hiroshi.cimoc.ui.activity.MainActivity; import com.hiroshi.cimoc.utils.DialogFactory; import com.hiroshi.cimoc.utils.PreferenceMaster; @@ -63,9 +63,9 @@ protected void initView() { mNightlyChoice = !mNightlyChoice; mNightlyBox.setChecked(mNightlyChoice); if (mNightlyChoice) { - ((BaseActivity) getActivity()).nightlyOn(); + ((MainActivity) getActivity()).nightlyOn(); } else { - ((BaseActivity) getActivity()).nightlyOff(); + ((MainActivity) getActivity()).nightlyOff(); } mPreference.putBoolean(PreferenceMaster.PREF_NIGHTLY, mNightlyChoice); } diff --git a/app/src/main/java/com/hiroshi/cimoc/utils/Decryption.java b/app/src/main/java/com/hiroshi/cimoc/utils/Decryption.java index 79697816..5b20c35b 100644 --- a/app/src/main/java/com/hiroshi/cimoc/utils/Decryption.java +++ b/app/src/main/java/com/hiroshi/cimoc/utils/Decryption.java @@ -16,7 +16,7 @@ */ public class Decryption { - public static String desDecrypt(String keyString, String cipherString) throws Exception { + public static String desDecrypt(String keyString, String cipherString) throws Exception { byte[] cipherBytes = Base64.decode(cipherString, Base64.DEFAULT); DESKeySpec keySpec = new DESKeySpec(keyString.getBytes()); Key key = SecretKeyFactory.getInstance("DES").generateSecret(keySpec); @@ -26,6 +26,11 @@ public static String desDecrypt(String keyString, String cipherString) throws Ex return new String(result, "UTF-8"); } + public static String base64Decrypt(String cipherString) throws Exception { + byte[] cipherBytes = Base64.decode(cipherString, Base64.DEFAULT); + return new String(cipherBytes, "UTF-8"); + } + public static String evalDecrypt(String jsCode) { Context rhino = Context.enter(); rhino.setOptimizationLevel(-1); diff --git a/app/src/main/java/com/hiroshi/cimoc/utils/MachiSoup.java b/app/src/main/java/com/hiroshi/cimoc/utils/MachiSoup.java index 6f0d02b2..e5c41e2f 100644 --- a/app/src/main/java/com/hiroshi/cimoc/utils/MachiSoup.java +++ b/app/src/main/java/com/hiroshi/cimoc/utils/MachiSoup.java @@ -15,27 +15,46 @@ public class MachiSoup { public static String match(String regex, String input, int group) { - Pattern pattern = Pattern.compile(regex); - Matcher matcher = pattern.matcher(input); - if (matcher.find()) { - return matcher.group(group); + try { + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(input); + if (matcher.find()) { + return matcher.group(group); + } + } catch (Exception e) { } return null; } public static String[] match(String regex, String input, int... group) { - Pattern pattern = Pattern.compile(regex); - Matcher matcher = pattern.matcher(input); - if (matcher.find()) { - String[] result = new String[group.length]; - for (int i = 0; i != result.length; ++i) { - result[i] = matcher.group(group[i]); + try { + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(input); + if (matcher.find()) { + String[] result = new String[group.length]; + for (int i = 0; i != result.length; ++i) { + result[i] = matcher.group(group[i]); + } + return result; } - return result; + } catch (Exception e) { } return null; } + public static List matchAll(String regex, String input, int group) { + LinkedList list = new LinkedList<>(); + try { + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(input); + while (matcher.find()) { + list.add(matcher.group(group)); + } + } catch (Exception e) { + } + return list; + } + public static Node body(String html) { return new Node(Jsoup.parse(html).body()); } diff --git a/app/src/main/res/drawable/flag_comic_new.xml b/app/src/main/res/drawable/flag_comic_new.xml new file mode 100644 index 00000000..bf8101fb --- /dev/null +++ b/app/src/main/res/drawable/flag_comic_new.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/custom_back_btn.xml b/app/src/main/res/layout/custom_back_btn.xml index 5cfc98b0..d8000385 100644 --- a/app/src/main/res/layout/custom_back_btn.xml +++ b/app/src/main/res/layout/custom_back_btn.xml @@ -7,12 +7,12 @@ android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:visibility="invisible" - android:padding="4dp" android:background="@color/trans_grey"> \ No newline at end of file diff --git a/app/src/main/res/layout/custom_toolbar.xml b/app/src/main/res/layout/custom_toolbar.xml index d2709462..3252a5ad 100644 --- a/app/src/main/res/layout/custom_toolbar.xml +++ b/app/src/main/res/layout/custom_toolbar.xml @@ -1,10 +1,8 @@ \ No newline at end of file + android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_about.xml b/app/src/main/res/layout/fragment_about.xml index 58a0c8ab..0ba87d0b 100644 --- a/app/src/main/res/layout/fragment_about.xml +++ b/app/src/main/res/layout/fragment_about.xml @@ -77,5 +77,11 @@ android:paddingTop="2dp" android:textSize="14sp" android:text="@string/about_support_account"/> + \ No newline at end of file diff --git a/app/src/main/res/layout/item_comic.xml b/app/src/main/res/layout/item_comic.xml index 726b6009..a4a91d4e 100644 --- a/app/src/main/res/layout/item_comic.xml +++ b/app/src/main/res/layout/item_comic.xml @@ -14,18 +14,15 @@ android:layout_width="match_parent" android:layout_height="match_parent" fresco:actualImageScaleType="centerCrop"/> - + android:visibility="invisible" + android:src="@drawable/flag_comic_new"/> 动漫之家 - Dmzj 汗汗漫画 - HHAAZZ CC图库 - CCTuku + 有妖气 - U17 看漫画 - IKanman 动漫之家 - Dmzj 汗汗漫画 - HHAAZZ CC图库 - CCTuku - Ex绅士 - ExHentai + 有妖气 - U17 E绅士 - EHentai + Ex绅士 - ExHentai + + 0 + 1 + 2 + 3 + 4 + 100 + 101 + Cimoc 我的漫画 diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 2ee41fb3..45b6b2cf 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -15,4 +15,5 @@ #AA7F7F80 #AABEBEBE #AA000000 + #00FFFFFF diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 18048ee0..348dfe63 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -26,7 +26,6 @@ 是否删除该漫画 是否检查更新 - NEW 是否删除该历史纪录 是否清除所有历史纪录 @@ -71,6 +70,11 @@ 支持作者 如果喜欢本应用,不妨支持一下作者哟 支付宝账号:cimoc_app@163.com + cimoc_app@163.com + 该邮箱也用于意见反馈 + 邮箱已复制到剪切板 + 重启软件打开隐藏图源 + 重启软件关闭隐藏图源 操作确认 确定 @@ -80,6 +84,7 @@ 动漫之家 汗汗漫画 CC图库 + 有妖气 E-Hentai ExHentai From 6765509487df96cfcd3cc83e43547f0122d01092 Mon Sep 17 00:00:00 2001 From: hiroshi Date: Sat, 13 Aug 2016 00:02:24 +0800 Subject: [PATCH 007/521] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=BB=91=E8=89=B2?= =?UTF-8?q?=E4=B8=BB=E9=A2=98=20=E5=A2=9E=E5=8A=A0=E5=9B=BE=E6=BA=90?= =?UTF-8?q?=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/dictionaries/Hiroshi.xml | 1 + app/build.gradle | 10 +- app/src/main/AndroidManifest.xml | 9 +- .../com/hiroshi/cimoc/CimocApplication.java | 15 +- .../com/hiroshi/cimoc/core/DBOpenHelper.java | 52 ++++++ .../java/com/hiroshi/cimoc/core/Kami.java | 102 ----------- .../{utils => core}/PreferenceMaster.java | 4 +- .../core/{ => manager}/ComicManager.java | 35 ++-- .../cimoc/core/manager/SourceManager.java | 167 ++++++++++++++++++ .../cimoc/core/{ => source}/CCTuku.java | 11 +- .../hiroshi/cimoc/core/{ => source}/Dmzj.java | 7 +- .../cimoc/core/{ => source}/EHentai.java | 7 +- .../cimoc/core/{ => source}/ExHentai.java | 7 +- .../cimoc/core/{ => source}/HHAAZZ.java | 7 +- .../cimoc/core/{ => source}/IKanman.java | 13 +- .../hiroshi/cimoc/core/{ => source}/U17.java | 11 +- .../com/hiroshi/cimoc/core/source/Wnacg.java | 106 +++++++++++ .../cimoc/core/{ => source}/base/Manga.java | 2 +- .../java/com/hiroshi/cimoc/model/Comic.java | 17 +- .../com/hiroshi/cimoc/model/EventMessage.java | 1 + .../java/com/hiroshi/cimoc/model/Source.java | 54 ++++++ .../cimoc/presenter/CimocPresenter.java | 44 +++++ .../cimoc/presenter/DetailPresenter.java | 8 +- .../cimoc/presenter/FavoritePresenter.java | 19 +- .../cimoc/presenter/HistoryPresenter.java | 24 ++- .../cimoc/presenter/MainPresenter.java | 8 + .../cimoc/presenter/ReaderPresenter.java | 6 +- .../cimoc/presenter/ResultPresenter.java | 10 +- .../cimoc/presenter/SettingsPresenter.java | 8 +- .../cimoc/presenter/SourcePresenter.java | 59 +++++++ .../cimoc/ui/activity/BaseActivity.java | 38 ++-- .../cimoc/ui/activity/MainActivity.java | 31 +++- .../cimoc/ui/activity/PageReaderActivity.java | 2 +- .../cimoc/ui/activity/ReaderActivity.java | 15 +- .../cimoc/ui/activity/ResultActivity.java | 11 +- .../ui/activity/StreamReaderActivity.java | 12 +- .../cimoc/ui/adapter/ComicAdapter.java | 12 +- .../cimoc/ui/adapter/PicturePageAdapter.java | 11 ++ .../ui/adapter/PictureStreamAdapter.java | 48 ++++- .../cimoc/ui/adapter/PreloadAdapter.java | 8 +- .../cimoc/ui/adapter/ResultAdapter.java | 17 +- .../cimoc/ui/adapter/SourceAdapter.java | 79 +++++++++ .../cimoc/ui/fragment/AboutFragment.java | 20 --- .../cimoc/ui/fragment/CimocFragment.java | 25 ++- .../cimoc/ui/fragment/FavoriteFragment.java | 19 +- .../cimoc/ui/fragment/HistoryFragment.java | 23 ++- .../cimoc/ui/fragment/SettingsFragment.java | 27 +-- .../cimoc/ui/fragment/SourceFragment.java | 101 +++++++++++ .../cimoc/utils/ControllerBuilderFactory.java | 26 ++- .../{Decryption.java => DecryptionUtils.java} | 2 +- .../hiroshi/cimoc/utils/DialogFactory.java | 6 +- .../main/res/color/button_chapter_color.xml | 2 +- .../res/color/button_chapter_color_dark.xml | 5 + .../res/drawable-hdpi/ic_add_white_24dp.png | Bin 0 -> 127 bytes .../res/drawable-xhdpi/ic_add_white_24dp.png | Bin 0 -> 97 bytes .../res/drawable-xxhdpi/ic_add_white_24dp.png | Bin 0 -> 97 bytes .../res/drawable/button_chapter_selector.xml | 12 +- .../drawable/button_chapter_selector_dark.xml | 39 ++++ app/src/main/res/drawable/progress_trans.xml | 4 +- .../main/res/drawable/progress_trans_dark.xml | 24 +++ app/src/main/res/layout/activity_detail.xml | 5 +- app/src/main/res/layout/activity_main.xml | 4 +- .../main/res/layout/activity_page_reader.xml | 1 + .../res/layout/activity_stream_reader.xml | 1 + app/src/main/res/layout/activtiy_result.xml | 8 +- app/src/main/res/layout/custom_mask.xml | 10 ++ app/src/main/res/layout/custom_seek_bar.xml | 6 +- app/src/main/res/layout/custom_toolbar.xml | 3 +- app/src/main/res/layout/dialog_add_source.xml | 17 ++ app/src/main/res/layout/fragment_about.xml | 5 +- app/src/main/res/layout/fragment_favorite.xml | 4 +- app/src/main/res/layout/fragment_history.xml | 19 +- app/src/main/res/layout/fragment_settings.xml | 50 ++++-- app/src/main/res/layout/fragment_source.xml | 23 +++ app/src/main/res/layout/item_chapter.xml | 4 +- app/src/main/res/layout/item_comic.xml | 4 +- app/src/main/res/layout/item_picture.xml | 2 +- app/src/main/res/layout/item_result.xml | 8 +- app/src/main/res/layout/item_source.xml | 31 ++++ app/src/main/res/menu/drawer_menu.xml | 3 + app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 2653 -> 508 bytes app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 1728 -> 278 bytes app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 4590 -> 657 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 7241 -> 967 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 5730 -> 1275 bytes app/src/main/res/values-v19/styles.xml | 15 ++ app/src/main/res/values/arrays.xml | 16 -- app/src/main/res/values/attrs.xml | 8 + app/src/main/res/values/colors.xml | 20 +-- app/src/main/res/values/strings.xml | 20 ++- app/src/main/res/values/styles.xml | 45 ++++- build.gradle | 2 +- 92 files changed, 1323 insertions(+), 454 deletions(-) create mode 100644 app/src/main/java/com/hiroshi/cimoc/core/DBOpenHelper.java delete mode 100644 app/src/main/java/com/hiroshi/cimoc/core/Kami.java rename app/src/main/java/com/hiroshi/cimoc/{utils => core}/PreferenceMaster.java (96%) rename app/src/main/java/com/hiroshi/cimoc/core/{ => manager}/ComicManager.java (90%) create mode 100644 app/src/main/java/com/hiroshi/cimoc/core/manager/SourceManager.java rename app/src/main/java/com/hiroshi/cimoc/core/{ => source}/CCTuku.java (93%) rename app/src/main/java/com/hiroshi/cimoc/core/{ => source}/Dmzj.java (95%) rename app/src/main/java/com/hiroshi/cimoc/core/{ => source}/EHentai.java (94%) rename app/src/main/java/com/hiroshi/cimoc/core/{ => source}/ExHentai.java (95%) rename app/src/main/java/com/hiroshi/cimoc/core/{ => source}/HHAAZZ.java (95%) rename app/src/main/java/com/hiroshi/cimoc/core/{ => source}/IKanman.java (90%) rename app/src/main/java/com/hiroshi/cimoc/core/{ => source}/U17.java (92%) create mode 100644 app/src/main/java/com/hiroshi/cimoc/core/source/Wnacg.java rename app/src/main/java/com/hiroshi/cimoc/core/{ => source}/base/Manga.java (99%) create mode 100644 app/src/main/java/com/hiroshi/cimoc/model/Source.java create mode 100644 app/src/main/java/com/hiroshi/cimoc/presenter/CimocPresenter.java create mode 100644 app/src/main/java/com/hiroshi/cimoc/presenter/SourcePresenter.java create mode 100644 app/src/main/java/com/hiroshi/cimoc/ui/adapter/SourceAdapter.java create mode 100644 app/src/main/java/com/hiroshi/cimoc/ui/fragment/SourceFragment.java rename app/src/main/java/com/hiroshi/cimoc/utils/{Decryption.java => DecryptionUtils.java} (97%) create mode 100644 app/src/main/res/color/button_chapter_color_dark.xml create mode 100644 app/src/main/res/drawable-hdpi/ic_add_white_24dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_add_white_24dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_add_white_24dp.png create mode 100644 app/src/main/res/drawable/button_chapter_selector_dark.xml create mode 100644 app/src/main/res/drawable/progress_trans_dark.xml create mode 100644 app/src/main/res/layout/custom_mask.xml create mode 100644 app/src/main/res/layout/dialog_add_source.xml create mode 100644 app/src/main/res/layout/fragment_source.xml create mode 100644 app/src/main/res/layout/item_source.xml create mode 100644 app/src/main/res/values-v19/styles.xml create mode 100644 app/src/main/res/values/attrs.xml diff --git a/.idea/dictionaries/Hiroshi.xml b/.idea/dictionaries/Hiroshi.xml index 805a85ae..956c5907 100644 --- a/.idea/dictionaries/Hiroshi.xml +++ b/.idea/dictionaries/Hiroshi.xml @@ -10,6 +10,7 @@ shtml tuku unfavorite + wnacg \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index c5615c38..1dfe5d5a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,7 +11,7 @@ android { minSdkVersion 15 targetSdkVersion 23 versionCode 1 - versionName "1.1.0" + versionName "1.1.1" resConfigs "en", "zh" } buildTypes { @@ -24,7 +24,7 @@ android { } greendao { - schemaVersion 1 + schemaVersion 2 } dependencies { @@ -33,10 +33,10 @@ dependencies { compile 'com.android.support:appcompat-v7:23.4.0' compile 'com.android.support:recyclerview-v7:23.4.0' compile 'com.android.support:design:23.4.0' - compile 'com.jakewharton:butterknife:8.1.0' - apt 'com.jakewharton:butterknife-compiler:8.1.0' + compile 'com.jakewharton:butterknife:8.2.1' + apt 'com.jakewharton:butterknife-compiler:8.2.1' compile 'org.greenrobot:eventbus:3.0.0' - compile 'org.greenrobot:greendao:3.0.1' + compile 'org.greenrobot:greendao:3.1.0' compile 'com.squareup.okhttp3:okhttp:3.4.1' compile 'com.facebook.fresco:fresco:0.12.0' compile 'com.facebook.fresco:imagepipeline-okhttp3:0.12.0' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index cedafbaf..e845dbb3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -14,7 +14,8 @@ android:theme="@style/AppTheme"> + android:name=".ui.activity.MainActivity" + android:windowSoftInputMode="adjustPan"> @@ -28,12 +29,10 @@ android:name=".ui.activity.DetailActivity"/> + android:name=".ui.activity.PageReaderActivity"/> + android:name=".ui.activity.StreamReaderActivity"/> diff --git a/app/src/main/java/com/hiroshi/cimoc/CimocApplication.java b/app/src/main/java/com/hiroshi/cimoc/CimocApplication.java index 6f8a5989..e9145212 100644 --- a/app/src/main/java/com/hiroshi/cimoc/CimocApplication.java +++ b/app/src/main/java/com/hiroshi/cimoc/CimocApplication.java @@ -4,11 +4,9 @@ import com.facebook.drawee.backends.pipeline.Fresco; import com.hiroshi.cimoc.model.DaoMaster; -import com.hiroshi.cimoc.model.DaoMaster.DevOpenHelper; import com.hiroshi.cimoc.model.DaoSession; -import com.hiroshi.cimoc.utils.PreferenceMaster; - -import org.greenrobot.greendao.database.Database; +import com.hiroshi.cimoc.core.DBOpenHelper; +import com.hiroshi.cimoc.core.PreferenceMaster; import okhttp3.OkHttpClient; @@ -24,17 +22,12 @@ public class CimocApplication extends Application { @Override public void onCreate() { super.onCreate(); - initDatabase(); + DBOpenHelper helper = new DBOpenHelper(this, "cimoc.db"); + daoSession = new DaoMaster(helper.getWritableDatabase()).newSession(); preferences = new PreferenceMaster(getApplicationContext()); Fresco.initialize(this); } - private void initDatabase() { - DevOpenHelper helper = new DevOpenHelper(this, "cimoc.db"); - Database db = helper.getWritableDb(); - daoSession = new DaoMaster(db).newSession(); - } - public static DaoSession getDaoSession() { return daoSession; } diff --git a/app/src/main/java/com/hiroshi/cimoc/core/DBOpenHelper.java b/app/src/main/java/com/hiroshi/cimoc/core/DBOpenHelper.java new file mode 100644 index 00000000..6874dc97 --- /dev/null +++ b/app/src/main/java/com/hiroshi/cimoc/core/DBOpenHelper.java @@ -0,0 +1,52 @@ +package com.hiroshi.cimoc.core; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; + +import com.hiroshi.cimoc.core.manager.SourceManager; +import com.hiroshi.cimoc.model.DaoMaster; +import com.hiroshi.cimoc.model.Source; +import com.hiroshi.cimoc.model.SourceDao; + +import org.greenrobot.greendao.database.Database; + +/** + * Created by Hiroshi on 2016/8/12. + */ +public class DBOpenHelper extends DaoMaster.OpenHelper { + + public DBOpenHelper(Context context, String name) { + super(context, name); + } + + public DBOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) { + super(context, name, factory); + } + + @Override + public void onCreate(Database db) { + super.onCreate(db); + initSource(db); + } + + @Override + public void onUpgrade(Database db, int oldVersion, int newVersion) { + switch (newVersion) { + case 2: + SourceDao.createTable(db, false); + initSource(db); + } + } + + private void initSource(Database db) { + SourceDao dao = new DaoMaster(db).newSession().getSourceDao(); + Source[] array = new Source[5]; + array[0] = new Source(null, SourceManager.SOURCE_IKANMAN, true); + array[1] = new Source(null, SourceManager.SOURCE_DMZJ, true); + array[2] = new Source(null, SourceManager.SOURCE_HHAAZZ, true); + array[3] = new Source(null, SourceManager.SOURCE_CCTUKU, true); + array[4] = new Source(null, SourceManager.SOURCE_U17, true); + dao.insertInTx(array); + } + +} diff --git a/app/src/main/java/com/hiroshi/cimoc/core/Kami.java b/app/src/main/java/com/hiroshi/cimoc/core/Kami.java deleted file mode 100644 index ccfc5853..00000000 --- a/app/src/main/java/com/hiroshi/cimoc/core/Kami.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.hiroshi.cimoc.core; - -import com.hiroshi.cimoc.R; -import com.hiroshi.cimoc.core.base.Manga; - -/** - * Created by Hiroshi on 2016/7/3. - */ -public class Kami { - - public static final int SOURCE_IKANMAN = 0; - public static final int SOURCE_DMZJ = 1; - public static final int SOURCE_HHAAZZ = 2; - public static final int SOURCE_CCTUKU = 3; - public static final int SOURCE_U17 = 4; - public static final int SOURCE_EHENTAI = 100; - public static final int SOURCE_EXHENTAI = 101; - - public static int getSourceTitle(int id) { - switch (id) { - default: - case SOURCE_IKANMAN: - return R.string.source_ikanman; - case SOURCE_DMZJ: - return R.string.source_dmzj; - case SOURCE_HHAAZZ: - return R.string.source_hhaazz; - case SOURCE_CCTUKU: - return R.string.source_cctuku; - case SOURCE_U17: - return R.string.source_u17; - case SOURCE_EHENTAI: - return R.string.source_ehentai; - case SOURCE_EXHENTAI: - return R.string.source_exhentai; - } - } - - public static String getReferer(int id) { - switch (id) { - default: - case SOURCE_IKANMAN: - return "http://m.ikanman.com"; - case SOURCE_DMZJ: - return "http://m.dmzj.com/"; - case SOURCE_HHAAZZ: - return "http://hhaazz.com"; - case SOURCE_CCTUKU: - return "http://m.tuku.cc"; - case SOURCE_U17: - return "http://www.u17.com"; - case SOURCE_EHENTAI: - return "http://lofi.e-hentai.org"; - case SOURCE_EXHENTAI: - return "https://exhentai.org"; - } - } - - private static Manga mIkanman, mDmzj, mHHAAZZ, mCCTuku, mU17, mExHentai, mEHentai; - - public static Manga getManga(int id) { - switch (id) { - default: - case SOURCE_IKANMAN: - if (mIkanman == null) { - mIkanman = new IKanman(); - } - return mIkanman; - case SOURCE_DMZJ: - if (mDmzj == null) { - mDmzj = new Dmzj(); - } - return mDmzj; - case SOURCE_HHAAZZ: - if (mHHAAZZ == null) { - mHHAAZZ = new HHAAZZ(); - } - return mHHAAZZ; - case SOURCE_CCTUKU: - if (mCCTuku == null) { - mCCTuku = new CCTuku(); - } - return mCCTuku; - case SOURCE_U17: - if (mU17 == null) { - mU17 = new U17(); - } - return mU17; - case SOURCE_EHENTAI: - if (mEHentai == null) { - mEHentai = new EHentai(); - } - return mEHentai; - case SOURCE_EXHENTAI: - if (mExHentai == null) { - mExHentai = new ExHentai(); - } - return mExHentai; - } - } - -} diff --git a/app/src/main/java/com/hiroshi/cimoc/utils/PreferenceMaster.java b/app/src/main/java/com/hiroshi/cimoc/core/PreferenceMaster.java similarity index 96% rename from app/src/main/java/com/hiroshi/cimoc/utils/PreferenceMaster.java rename to app/src/main/java/com/hiroshi/cimoc/core/PreferenceMaster.java index 276b6c33..9d3ce8b7 100644 --- a/app/src/main/java/com/hiroshi/cimoc/utils/PreferenceMaster.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/PreferenceMaster.java @@ -1,4 +1,4 @@ -package com.hiroshi.cimoc.utils; +package com.hiroshi.cimoc.core; import android.content.Context; import android.content.SharedPreferences; @@ -18,11 +18,11 @@ public class PreferenceMaster { public static final int HOME_FAVORITE = 1; public static final int HOME_HISTORY = 2; - public static final String PREF_EX = "pref_ex"; public static final String PREF_HOME = "pref_home"; public static final String PREF_MODE = "pref_mode"; public static final String PREF_VOLUME = "pref_volume"; public static final String PREF_NIGHTLY = "pref_nightly"; + public static final String PREF_SPLIT = "pref_split"; private static final String PREFERENCES_NAME = "cimoc_preferences"; diff --git a/app/src/main/java/com/hiroshi/cimoc/core/ComicManager.java b/app/src/main/java/com/hiroshi/cimoc/core/manager/ComicManager.java similarity index 90% rename from app/src/main/java/com/hiroshi/cimoc/core/ComicManager.java rename to app/src/main/java/com/hiroshi/cimoc/core/manager/ComicManager.java index 73781929..499a706f 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/ComicManager.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/manager/ComicManager.java @@ -1,4 +1,4 @@ -package com.hiroshi.cimoc.core; +package com.hiroshi.cimoc.core.manager; import android.database.Cursor; @@ -74,7 +74,21 @@ public void run() { }); } - public void removeFavorite(long id) { + public void deleteBySource(final int source) { + mComicDao.getSession().runInTx(new Runnable() { + @Override + public void run() { + List list = mComicDao.queryBuilder() + .where(Properties.Source.eq(source)) + .list(); + for (Comic comic : list) { + mComicDao.delete(comic); + } + } + }); + } + + public void deleteFavorite(long id) { Comic comic = mComicDao.load(id); if (comic.getHistory() == null) { mComicDao.delete(comic); @@ -84,7 +98,7 @@ public void removeFavorite(long id) { } } - public void removeHistory(long id) { + public void deleteHistory(long id) { Comic comic = mComicDao.load(id); if (comic.getFavorite() == null) { mComicDao.delete(comic); @@ -121,19 +135,8 @@ public MiniComic[] arrayFavorite() { .where(ComicDao.Properties.Favorite.isNotNull()) .buildCursor() .query(); - MiniComic[] array = new MiniComic[cursor.getCount()]; - int count = 0; - while (cursor.moveToNext()) { - long id = cursor.getLong(0); - int source = cursor.getInt(1); - String cid = cursor.getString(2); - String title = cursor.getString(3); - String cover = cursor.getString(4); - String update = cursor.getString(5); - array[count++] = new MiniComic(id, source, cid, title, cover, update, false); - } - cursor.close(); - return array; + List list = listByCursor(cursor); + return list.toArray(new MiniComic[cursor.getCount()]); } public List listFavorite() { diff --git a/app/src/main/java/com/hiroshi/cimoc/core/manager/SourceManager.java b/app/src/main/java/com/hiroshi/cimoc/core/manager/SourceManager.java new file mode 100644 index 00000000..de391af0 --- /dev/null +++ b/app/src/main/java/com/hiroshi/cimoc/core/manager/SourceManager.java @@ -0,0 +1,167 @@ +package com.hiroshi.cimoc.core.manager; + +import android.util.SparseArray; + +import com.hiroshi.cimoc.CimocApplication; +import com.hiroshi.cimoc.R; +import com.hiroshi.cimoc.core.source.CCTuku; +import com.hiroshi.cimoc.core.source.Dmzj; +import com.hiroshi.cimoc.core.source.EHentai; +import com.hiroshi.cimoc.core.source.ExHentai; +import com.hiroshi.cimoc.core.source.HHAAZZ; +import com.hiroshi.cimoc.core.source.IKanman; +import com.hiroshi.cimoc.core.source.U17; +import com.hiroshi.cimoc.core.source.base.Manga; +import com.hiroshi.cimoc.model.Source; +import com.hiroshi.cimoc.model.SourceDao; +import com.hiroshi.cimoc.model.SourceDao.Properties; + +import java.util.List; + +/** + * Created by Hiroshi on 2016/8/11. + */ +public class SourceManager { + + public static final int SOURCE_IKANMAN = 0; + public static final int SOURCE_DMZJ = 1; + public static final int SOURCE_HHAAZZ = 2; + public static final int SOURCE_CCTUKU = 3; + public static final int SOURCE_U17 = 4; + + public static final int SOURCE_EHENTAI = 100; + public static final int SOURCE_EXHENTAI = 101; + public static final int SOURCE_NHENTAI = 102; + public static final int SOURCE_WNACG = 103; + + private static SourceManager mSourceManager; + + private SourceDao mSourceDao; + + private SourceManager() { + mSourceDao = CimocApplication.getDaoSession().getSourceDao(); + } + + public List list() { + return mSourceDao.queryBuilder().orderAsc(Properties.Sid).list(); + } + + public List listEnable() { + return mSourceDao.queryBuilder().where(Properties.Enable.eq(true)).orderAsc(Properties.Sid).list(); + } + + public boolean exist(int sid) { + return mSourceDao.queryBuilder().where(Properties.Sid.eq(sid)).unique() != null; + } + + public long insert(int sid) { + return mSourceDao.insert(new Source(null, sid, true)); + } + + public void delete(long id) { + mSourceDao.deleteByKey(id); + } + + public void update(Source source) { + mSourceDao.update(source); + } + + public static int getTitle(int id) { + switch (id) { + case SOURCE_IKANMAN: + return R.string.source_ikanman; + case SOURCE_DMZJ: + return R.string.source_dmzj; + case SOURCE_HHAAZZ: + return R.string.source_hhaazz; + case SOURCE_CCTUKU: + return R.string.source_cctuku; + case SOURCE_U17: + return R.string.source_u17; + case SOURCE_EHENTAI: + return R.string.source_ehentai; + case SOURCE_EXHENTAI: + return R.string.source_exhentai; + } + return R.string.common_null; + } + + public static int getId(String key) { + switch (key) { + case "IKanman": + return SOURCE_IKANMAN; + case "DMZJ": + return SOURCE_DMZJ; + case "HHAAZZ": + return SOURCE_HHAAZZ; + case "CCTuku": + return SOURCE_CCTUKU; + case "U17": + return SOURCE_U17; + case "EHentai": + return SOURCE_EHENTAI; + case "ExHentai": + return SOURCE_EXHENTAI; + } + return -1; + } + + private static SparseArray sparseArray = new SparseArray<>(); + + public static Manga getManga(int source) { + Manga manga = sparseArray.get(source); + switch (source) { + case SOURCE_IKANMAN: + if (manga == null) { + manga = new IKanman(); + sparseArray.put(SOURCE_IKANMAN, manga); + } + break; + case SOURCE_DMZJ: + if (manga == null) { + manga = new Dmzj(); + sparseArray.put(SOURCE_IKANMAN, manga); + } + break; + case SOURCE_HHAAZZ: + if (manga == null) { + manga = new HHAAZZ(); + sparseArray.put(SOURCE_IKANMAN, manga); + } + break; + case SOURCE_CCTUKU: + if (manga == null) { + manga = new CCTuku(); + sparseArray.put(SOURCE_IKANMAN, manga); + } + break; + case SOURCE_U17: + if (manga == null) { + manga = new U17(); + sparseArray.put(SOURCE_IKANMAN, manga); + } + break; + case SOURCE_EHENTAI: + if (manga == null) { + manga = new EHentai(); + sparseArray.put(SOURCE_IKANMAN, manga); + } + break; + case SOURCE_EXHENTAI: + if (manga == null) { + manga = new ExHentai(); + sparseArray.put(SOURCE_IKANMAN, manga); + } + break; + } + return manga; + } + + public static SourceManager getInstance() { + if (mSourceManager == null) { + mSourceManager = new SourceManager(); + } + return mSourceManager; + } + +} diff --git a/app/src/main/java/com/hiroshi/cimoc/core/CCTuku.java b/app/src/main/java/com/hiroshi/cimoc/core/source/CCTuku.java similarity index 93% rename from app/src/main/java/com/hiroshi/cimoc/core/CCTuku.java rename to app/src/main/java/com/hiroshi/cimoc/core/source/CCTuku.java index 7fe919de..e7ec9469 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/CCTuku.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/source/CCTuku.java @@ -1,9 +1,10 @@ -package com.hiroshi.cimoc.core; +package com.hiroshi.cimoc.core.source; -import com.hiroshi.cimoc.core.base.Manga; +import com.hiroshi.cimoc.core.source.base.Manga; +import com.hiroshi.cimoc.core.manager.SourceManager; import com.hiroshi.cimoc.model.Chapter; import com.hiroshi.cimoc.model.Comic; -import com.hiroshi.cimoc.utils.Decryption; +import com.hiroshi.cimoc.utils.DecryptionUtils; import com.hiroshi.cimoc.utils.MachiSoup; import com.hiroshi.cimoc.utils.MachiSoup.Node; @@ -19,7 +20,7 @@ public class CCTuku extends Manga { public CCTuku() { - super(Kami.SOURCE_CCTUKU, "http://m.tuku.cc"); + super(SourceManager.SOURCE_CCTUKU, "http://m.tuku.cc"); } @Override @@ -86,7 +87,7 @@ protected String[] parseBrowse(String html) { String[] rs = MachiSoup.match("serverUrl = '(.*?)'[\\s\\S]*?eval(.*?)\\n;", html, 1, 2); if (rs != null) { try { - String result = Decryption.evalDecrypt(rs[1]); + String result = DecryptionUtils.evalDecrypt(rs[1]); String[] array = MachiSoup.match("pic_url='(.*?)';.*?tpf=(\\d+?);.*pages=(\\d+?);.*?pid=(.*?);.*?pic_extname='(.*?)';", result, 1, 2, 3, 4, 5); if (array != null) { int tpf = Integer.parseInt(array[1]) + 1; diff --git a/app/src/main/java/com/hiroshi/cimoc/core/Dmzj.java b/app/src/main/java/com/hiroshi/cimoc/core/source/Dmzj.java similarity index 95% rename from app/src/main/java/com/hiroshi/cimoc/core/Dmzj.java rename to app/src/main/java/com/hiroshi/cimoc/core/source/Dmzj.java index 592127dd..b63e69f8 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/Dmzj.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/source/Dmzj.java @@ -1,6 +1,7 @@ -package com.hiroshi.cimoc.core; +package com.hiroshi.cimoc.core.source; -import com.hiroshi.cimoc.core.base.Manga; +import com.hiroshi.cimoc.core.source.base.Manga; +import com.hiroshi.cimoc.core.manager.SourceManager; import com.hiroshi.cimoc.model.Chapter; import com.hiroshi.cimoc.model.Comic; import com.hiroshi.cimoc.utils.MachiSoup; @@ -22,7 +23,7 @@ public class Dmzj extends Manga { public Dmzj() { - super(Kami.SOURCE_DMZJ, "http://m.dmzj.com"); + super(SourceManager.SOURCE_DMZJ, "http://m.dmzj.com"); } @Override diff --git a/app/src/main/java/com/hiroshi/cimoc/core/EHentai.java b/app/src/main/java/com/hiroshi/cimoc/core/source/EHentai.java similarity index 94% rename from app/src/main/java/com/hiroshi/cimoc/core/EHentai.java rename to app/src/main/java/com/hiroshi/cimoc/core/source/EHentai.java index e408fb42..74982050 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/EHentai.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/source/EHentai.java @@ -1,6 +1,7 @@ -package com.hiroshi.cimoc.core; +package com.hiroshi.cimoc.core.source; -import com.hiroshi.cimoc.core.base.Manga; +import com.hiroshi.cimoc.core.source.base.Manga; +import com.hiroshi.cimoc.core.manager.SourceManager; import com.hiroshi.cimoc.model.Chapter; import com.hiroshi.cimoc.model.Comic; import com.hiroshi.cimoc.utils.MachiSoup; @@ -17,7 +18,7 @@ public class EHentai extends Manga { public EHentai() { - super(Kami.SOURCE_EHENTAI, "http://lofi.e-hentai.org"); + super(SourceManager.SOURCE_EHENTAI, "http://lofi.e-hentai.org"); } @Override diff --git a/app/src/main/java/com/hiroshi/cimoc/core/ExHentai.java b/app/src/main/java/com/hiroshi/cimoc/core/source/ExHentai.java similarity index 95% rename from app/src/main/java/com/hiroshi/cimoc/core/ExHentai.java rename to app/src/main/java/com/hiroshi/cimoc/core/source/ExHentai.java index d43bdcd8..5d081a71 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/ExHentai.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/source/ExHentai.java @@ -1,6 +1,7 @@ -package com.hiroshi.cimoc.core; +package com.hiroshi.cimoc.core.source; -import com.hiroshi.cimoc.core.base.Manga; +import com.hiroshi.cimoc.core.source.base.Manga; +import com.hiroshi.cimoc.core.manager.SourceManager; import com.hiroshi.cimoc.model.Chapter; import com.hiroshi.cimoc.model.Comic; import com.hiroshi.cimoc.utils.MachiSoup; @@ -17,7 +18,7 @@ public class ExHentai extends Manga { public ExHentai() { - super(Kami.SOURCE_EXHENTAI, "https://exhentai.org"); + super(SourceManager.SOURCE_EXHENTAI, "https://exhentai.org"); } @Override diff --git a/app/src/main/java/com/hiroshi/cimoc/core/HHAAZZ.java b/app/src/main/java/com/hiroshi/cimoc/core/source/HHAAZZ.java similarity index 95% rename from app/src/main/java/com/hiroshi/cimoc/core/HHAAZZ.java rename to app/src/main/java/com/hiroshi/cimoc/core/source/HHAAZZ.java index 70a65a40..001b6eeb 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/HHAAZZ.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/source/HHAAZZ.java @@ -1,6 +1,7 @@ -package com.hiroshi.cimoc.core; +package com.hiroshi.cimoc.core.source; -import com.hiroshi.cimoc.core.base.Manga; +import com.hiroshi.cimoc.core.source.base.Manga; +import com.hiroshi.cimoc.core.manager.SourceManager; import com.hiroshi.cimoc.model.Chapter; import com.hiroshi.cimoc.model.Comic; import com.hiroshi.cimoc.utils.MachiSoup; @@ -18,7 +19,7 @@ public class HHAAZZ extends Manga { public HHAAZZ() { - super(Kami.SOURCE_HHAAZZ, "http://hhaazz.com"); + super(SourceManager.SOURCE_HHAAZZ, "http://hhaazz.com"); } @Override diff --git a/app/src/main/java/com/hiroshi/cimoc/core/IKanman.java b/app/src/main/java/com/hiroshi/cimoc/core/source/IKanman.java similarity index 90% rename from app/src/main/java/com/hiroshi/cimoc/core/IKanman.java rename to app/src/main/java/com/hiroshi/cimoc/core/source/IKanman.java index c0c72e4b..06eefe92 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/IKanman.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/source/IKanman.java @@ -1,9 +1,10 @@ -package com.hiroshi.cimoc.core; +package com.hiroshi.cimoc.core.source; -import com.hiroshi.cimoc.core.base.Manga; +import com.hiroshi.cimoc.core.source.base.Manga; +import com.hiroshi.cimoc.core.manager.SourceManager; import com.hiroshi.cimoc.model.Chapter; import com.hiroshi.cimoc.model.Comic; -import com.hiroshi.cimoc.utils.Decryption; +import com.hiroshi.cimoc.utils.DecryptionUtils; import com.hiroshi.cimoc.utils.MachiSoup; import com.hiroshi.cimoc.utils.MachiSoup.Node; @@ -21,7 +22,7 @@ public class IKanman extends Manga { public IKanman() { - super(Kami.SOURCE_IKANMAN, "http://m.ikanman.com"); + super(SourceManager.SOURCE_IKANMAN, "http://m.ikanman.com"); } @Override @@ -88,8 +89,8 @@ protected String[] parseBrowse(String html) { try { String cipherStr = str.substring(8); String keyStr = str.substring(0, 8); - String packed = Decryption.desDecrypt(keyStr, cipherStr); - String result = Decryption.evalDecrypt(packed.substring(4)); + String packed = DecryptionUtils.desDecrypt(keyStr, cipherStr); + String result = DecryptionUtils.evalDecrypt(packed.substring(4)); String jsonString = result.substring(11, result.length() - 9); JSONObject info = new JSONObject(jsonString); diff --git a/app/src/main/java/com/hiroshi/cimoc/core/U17.java b/app/src/main/java/com/hiroshi/cimoc/core/source/U17.java similarity index 92% rename from app/src/main/java/com/hiroshi/cimoc/core/U17.java rename to app/src/main/java/com/hiroshi/cimoc/core/source/U17.java index a858dcee..f69eb237 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/U17.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/source/U17.java @@ -1,9 +1,10 @@ -package com.hiroshi.cimoc.core; +package com.hiroshi.cimoc.core.source; -import com.hiroshi.cimoc.core.base.Manga; +import com.hiroshi.cimoc.core.source.base.Manga; +import com.hiroshi.cimoc.core.manager.SourceManager; import com.hiroshi.cimoc.model.Chapter; import com.hiroshi.cimoc.model.Comic; -import com.hiroshi.cimoc.utils.Decryption; +import com.hiroshi.cimoc.utils.DecryptionUtils; import com.hiroshi.cimoc.utils.MachiSoup; import com.hiroshi.cimoc.utils.MachiSoup.Node; @@ -18,7 +19,7 @@ public class U17 extends Manga { public U17() { - super(Kami.SOURCE_U17, "http://www.u17.com"); + super(SourceManager.SOURCE_U17, "http://www.u17.com"); } @Override @@ -84,7 +85,7 @@ protected String[] parseBrowse(String html) { try { String[] images = new String[list.size()]; for (int i = 0; i != images.length; ++i) { - images[i] = Decryption.base64Decrypt(list.get(i)); + images[i] = DecryptionUtils.base64Decrypt(list.get(i)); } return images; } catch (Exception e) { diff --git a/app/src/main/java/com/hiroshi/cimoc/core/source/Wnacg.java b/app/src/main/java/com/hiroshi/cimoc/core/source/Wnacg.java new file mode 100644 index 00000000..020d98e5 --- /dev/null +++ b/app/src/main/java/com/hiroshi/cimoc/core/source/Wnacg.java @@ -0,0 +1,106 @@ +package com.hiroshi.cimoc.core.source; + +import com.hiroshi.cimoc.core.source.base.Manga; +import com.hiroshi.cimoc.core.manager.SourceManager; +import com.hiroshi.cimoc.model.Chapter; +import com.hiroshi.cimoc.model.Comic; +import com.hiroshi.cimoc.utils.MachiSoup; +import com.hiroshi.cimoc.utils.MachiSoup.Node; + +import java.util.LinkedList; +import java.util.List; + +import okhttp3.Request; + +/** + * Created by Hiroshi on 2016/8/9. + */ +public class Wnacg extends Manga { + + public Wnacg() { + super(SourceManager.SOURCE_WNACG, "http://www.wnacg.com"); + } + + @Override + protected Request buildSearchRequest(String keyword, int page) { + String url = host + "/albums-index-page-" + page + "-sname-" + keyword + ".html"; + return new Request.Builder().url(url).header("Cookie", "ipb_member_id=2145630; ipb_pass_hash=f883b5a9dd10234c9323957b96efbd8e").build(); + } + + @Override + protected List parseSearch(String html, int page) { + Node body = MachiSoup.body(html); + List list = new LinkedList<>(); + for (MachiSoup.Node node : body.list("#bodywrap > div.grid > div > ul > li")) { + String cid = node.attr("div.info > div.title > a", "href", "-|\\.", 3); + String title = node.text("div.info > div.title > a"); + String cover = node.attr("div.pic_box > a > img", "src"); + String update = node.text("div.info > div.info_col", 0, 10); + String author = node.text("td:eq(3) > div > a"); + list.add(new Comic(source, cid, title, cover, update, author, true)); + } + return list; + } + + @Override + protected Request buildIntoRequest(String cid) { + String url = host + "/g/" + cid; + return new Request.Builder().url(url).header("Cookie", "s=485adc1edc9d59a6a7d62cd15d1a7a213b333f5cb092bcc2d30c476419fbcb5555f19e27c606df9cdc56737cb920fe0855e9671c7109069401d8ede5b718f522; ipb_member_id=2145630; ipb_pass_hash=f883b5a9dd10234c9323957b96efbd8e; uconfig=ts_l;").build(); + } + + @Override + protected List parseInto(String html, Comic comic) { + List list = new LinkedList<>(); + MachiSoup.Node body = MachiSoup.body(html); + String length = body.text("#gdd > table > tbody > tr:eq(5) > td:eq(1)", " ", 0); + int size = Integer.parseInt(length) % 20 == 0 ? Integer.parseInt(length) / 20 : Integer.parseInt(length) / 20 + 1; + for (int i = 0; i != size; ++i) { + list.add(0, new Chapter("Ch" + i, String.valueOf(i))); + } + + String update = body.text("#gdd > table > tbody > tr:eq(0) > td:eq(1)", 0, 10); + String title = body.text("#gn"); + String intro = body.text("#gj"); + String author = body.text("#taglist > table > tbody > tr > td:eq(1) > div > a[id^=ta_artist]"); + String cover = body.attr("#gd1 > img", "src"); + comic.setInfo(title, cover, update, intro, author, true); + + return list; + } + + @Override + protected Request buildBrowseRequest(String cid, String path) { + String url = host + "/g/" + cid + "?p=" + path; + return new Request.Builder().url(url).header("Cookie", "s=485adc1edc9d59a6a7d62cd15d1a7a213b333f5cb092bcc2d30c476419fbcb5555f19e27c606df9cdc56737cb920fe0855e9671c7109069401d8ede5b718f522; ipb_member_id=2145630; ipb_pass_hash=f883b5a9dd10234c9323957b96efbd8e; uconfig=ts_l").build(); + } + + @Override + protected String[] parseBrowse(String html) { + MachiSoup.Node body = MachiSoup.body(html); + List list = body.list("#gdt > div > a"); + String[] array = new String[list.size()]; + for (int i = 0; i != array.length; ++i) { + String url = list.get(i).attr("href"); + Request request = new Request.Builder().url(url).header("Cookie", "ipb_member_id=2145630; ipb_pass_hash=f883b5a9dd10234c9323957b96efbd8e").build(); + String result = execute(request); + if (result != null) { + MachiSoup.Node node = MachiSoup.body(result); + array[i] = node.attr("#img", "src"); + } else { + array[i] = null; + } + } + return array; + } + + @Override + protected Request buildCheckRequest(String cid) { + return null; + } + + @Override + protected String parseCheck(String html) { + return null; + } + +} diff --git a/app/src/main/java/com/hiroshi/cimoc/core/base/Manga.java b/app/src/main/java/com/hiroshi/cimoc/core/source/base/Manga.java similarity index 99% rename from app/src/main/java/com/hiroshi/cimoc/core/base/Manga.java rename to app/src/main/java/com/hiroshi/cimoc/core/source/base/Manga.java index 142ec18d..c4fb12d2 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/base/Manga.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/source/base/Manga.java @@ -1,4 +1,4 @@ -package com.hiroshi.cimoc.core.base; +package com.hiroshi.cimoc.core.source.base; import com.hiroshi.cimoc.CimocApplication; import com.hiroshi.cimoc.model.Chapter; diff --git a/app/src/main/java/com/hiroshi/cimoc/model/Comic.java b/app/src/main/java/com/hiroshi/cimoc/model/Comic.java index 3dd8fdff..e940cc0a 100644 --- a/app/src/main/java/com/hiroshi/cimoc/model/Comic.java +++ b/app/src/main/java/com/hiroshi/cimoc/model/Comic.java @@ -13,7 +13,7 @@ public class Comic { @Id(autoincrement = true) private Long id; - @NotNull private Integer source; + @NotNull private int source; @NotNull private String cid; @NotNull private String title; @NotNull private String cover; @@ -27,10 +27,9 @@ public class Comic { @Transient private String author; @Transient private Boolean status; - @Generated(hash = 1262295933) - public Comic(Long id, @NotNull Integer source, @NotNull String cid, - @NotNull String title, @NotNull String cover, @NotNull String update, - Long favorite, Long history, String last, Integer page) { + @Generated(hash = 1562578524) + public Comic(Long id, int source, @NotNull String cid, @NotNull String title, @NotNull String cover, + @NotNull String update, Long favorite, Long history, String last, Integer page) { this.id = id; this.source = source; this.cid = cid; @@ -47,7 +46,7 @@ public Comic(Long id, @NotNull Integer source, @NotNull String cid, public Comic() { } - public Comic(Integer source, String cid, String title, String cover, String update, String author, Boolean status) { + public Comic(int source, String cid, String title, String cover, String update, String author, Boolean status) { this.source = source; this.cid = cid; this.title = title; @@ -57,7 +56,7 @@ public Comic(Integer source, String cid, String title, String cover, String upda this.status = status; } - public Comic(Integer source, String cid) { + public Comic(int source, String cid) { this.source = source; this.cid = cid; } @@ -164,11 +163,11 @@ public void setCid(String cid) { this.cid = cid; } - public Integer getSource() { + public int getSource() { return this.source; } - public void setSource(Integer source) { + public void setSource(int source) { this.source = source; } diff --git a/app/src/main/java/com/hiroshi/cimoc/model/EventMessage.java b/app/src/main/java/com/hiroshi/cimoc/model/EventMessage.java index 18f5171e..bf3be38e 100644 --- a/app/src/main/java/com/hiroshi/cimoc/model/EventMessage.java +++ b/app/src/main/java/com/hiroshi/cimoc/model/EventMessage.java @@ -19,6 +19,7 @@ public class EventMessage { public static final int COMIC_LAST_CHANGE = 12; public static final int DELETE_HISTORY = 13; public static final int RESTORE_FAVORITE = 14; + public static final int COMIC_DELETE = 15; private int type; private Object data; diff --git a/app/src/main/java/com/hiroshi/cimoc/model/Source.java b/app/src/main/java/com/hiroshi/cimoc/model/Source.java new file mode 100644 index 00000000..8064d62e --- /dev/null +++ b/app/src/main/java/com/hiroshi/cimoc/model/Source.java @@ -0,0 +1,54 @@ +package com.hiroshi.cimoc.model; + +import org.greenrobot.greendao.annotation.Entity; +import org.greenrobot.greendao.annotation.Generated; +import org.greenrobot.greendao.annotation.Id; +import org.greenrobot.greendao.annotation.NotNull; +import org.greenrobot.greendao.annotation.Unique; + +/** + * Created by Hiroshi on 2016/8/11. + */ +@Entity +public class Source { + + @Id private Long id; + @Unique private int sid; + @NotNull private boolean enable; + + public boolean getEnable() { + return this.enable; + } + + public void setEnable(boolean enable) { + this.enable = enable; + } + + public int getSid() { + return this.sid; + } + + public void setSid(int sid) { + this.sid = sid; + } + + public Long getId() { + return this.id; + } + + public void setId(Long id) { + this.id = id; + } + + @Generated(hash = 667633842) + public Source(Long id, int sid, boolean enable) { + this.id = id; + this.sid = sid; + this.enable = enable; + } + + @Generated(hash = 615387317) + public Source() { + } + +} diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/CimocPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/CimocPresenter.java new file mode 100644 index 00000000..1fe5bcd8 --- /dev/null +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/CimocPresenter.java @@ -0,0 +1,44 @@ +package com.hiroshi.cimoc.presenter; + +import com.hiroshi.cimoc.core.manager.SourceManager; +import com.hiroshi.cimoc.model.EventMessage; +import com.hiroshi.cimoc.model.Source; +import com.hiroshi.cimoc.ui.fragment.CimocFragment; + +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.List; + +/** + * Created by Hiroshi on 2016/8/12. + */ +public class CimocPresenter extends BasePresenter { + + private CimocFragment mCimocFragment; + private SourceManager mSourceManager; + private List mSourceList; + + public CimocPresenter(CimocFragment fragment) { + mCimocFragment = fragment; + mSourceManager = SourceManager.getInstance(); + } + + public String[] getItems() { + mSourceList = mSourceManager.listEnable(); + String[] items = new String[mSourceList.size()]; + for (int i = 0; i != items.length; ++i) { + items[i] = mCimocFragment.getString(SourceManager.getTitle(mSourceList.get(i).getSid())); + } + return items; + } + + public int getSid(int location) { + return mSourceList.get(location).getSid(); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onEvent(EventMessage msg) { + } + +} diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/DetailPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/DetailPresenter.java index f4398a60..e23c9f59 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/DetailPresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/DetailPresenter.java @@ -1,8 +1,8 @@ package com.hiroshi.cimoc.presenter; -import com.hiroshi.cimoc.core.ComicManager; -import com.hiroshi.cimoc.core.Kami; -import com.hiroshi.cimoc.core.base.Manga; +import com.hiroshi.cimoc.core.manager.ComicManager; +import com.hiroshi.cimoc.core.manager.SourceManager; +import com.hiroshi.cimoc.core.source.base.Manga; import com.hiroshi.cimoc.model.Chapter; import com.hiroshi.cimoc.model.Comic; import com.hiroshi.cimoc.model.EventMessage; @@ -30,7 +30,7 @@ public class DetailPresenter extends BasePresenter { public DetailPresenter(DetailActivity activity, Long id, int source, String cid) { mDetailActivity = activity; mComicManager = ComicManager.getInstance(); - mManga = Kami.getManga(source); + mManga = SourceManager.getManga(source); mComic = mComicManager.getComic(id, source, cid); } diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/FavoritePresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/FavoritePresenter.java index 07de244e..2bc05706 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/FavoritePresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/FavoritePresenter.java @@ -1,11 +1,8 @@ package com.hiroshi.cimoc.presenter; -import android.content.Intent; - -import com.hiroshi.cimoc.core.ComicManager; +import com.hiroshi.cimoc.core.manager.ComicManager; import com.hiroshi.cimoc.model.EventMessage; import com.hiroshi.cimoc.model.MiniComic; -import com.hiroshi.cimoc.ui.activity.DetailActivity; import com.hiroshi.cimoc.ui.fragment.FavoriteFragment; import org.greenrobot.eventbus.Subscribe; @@ -34,17 +31,12 @@ public MiniComic[] getComicArray() { return mComicManager.arrayFavorite(); } - public void onItemClick(MiniComic comic) { - Intent intent = DetailActivity.createIntent(mFavoriteFragment.getActivity(), comic.getId(), comic.getSource(), comic.getCid()); - mFavoriteFragment.startActivity(intent); - } - public void updateComic(List list) { mComicManager.updateFavorite(list); } - public void onPositiveClick(MiniComic comic) { - mComicManager.removeFavorite(comic.getId()); + public void deleteComic(MiniComic comic) { + mComicManager.deleteFavorite(comic.getId()); } @SuppressWarnings("unchecked") @@ -55,11 +47,14 @@ public void onEvent(EventMessage msg) { mFavoriteFragment.addItem((MiniComic) msg.getData()); break; case EventMessage.UN_FAVORITE_COMIC: - mFavoriteFragment.removeItem((Long) msg.getData()); + mFavoriteFragment.removeItem((long) msg.getData()); break; case EventMessage.RESTORE_FAVORITE: mFavoriteFragment.addItems((List) msg.getData()); break; + case EventMessage.COMIC_DELETE: + mFavoriteFragment.removeItems((int) msg.getData()); + break; } } diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/HistoryPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/HistoryPresenter.java index 3b381aa0..0c6adcf5 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/HistoryPresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/HistoryPresenter.java @@ -1,11 +1,9 @@ package com.hiroshi.cimoc.presenter; -import android.content.Intent; - -import com.hiroshi.cimoc.core.ComicManager; +import com.hiroshi.cimoc.R; +import com.hiroshi.cimoc.core.manager.ComicManager; import com.hiroshi.cimoc.model.EventMessage; import com.hiroshi.cimoc.model.MiniComic; -import com.hiroshi.cimoc.ui.activity.DetailActivity; import com.hiroshi.cimoc.ui.fragment.HistoryFragment; import org.greenrobot.eventbus.Subscribe; @@ -30,16 +28,11 @@ public List getComic() { return mComicManager.listHistory(); } - public void onItemClick(MiniComic comic) { - Intent intent = DetailActivity.createIntent(mHistoryFragment.getActivity(), comic.getId(), comic.getSource(), comic.getCid()); - mHistoryFragment.startActivity(intent); - } - - public void onPositiveClick(MiniComic comic) { - mComicManager.removeHistory(comic.getId()); + public void deleteHistory(MiniComic comic) { + mComicManager.deleteHistory(comic.getId()); } - public void onHistoryClearClick() { + public void clearHistory() { mComicManager.cleanHistory(); } @@ -50,10 +43,13 @@ public void onEvent(EventMessage msg) { mHistoryFragment.updateItem((MiniComic) msg.getData()); break; case EventMessage.DELETE_HISTORY: - int count = (int) msg.getData(); mHistoryFragment.clearItem(); mHistoryFragment.hideProgressDialog(); - mHistoryFragment.showSnackbar("删除成功 共 " + count + " 条记录"); + String text = mHistoryFragment.getString(R.string.history_clear_success) + (int) msg.getData(); + mHistoryFragment.showSnackbar(text); + break; + case EventMessage.COMIC_DELETE: + mHistoryFragment.removeItems((int) msg.getData()); break; } } diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/MainPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/MainPresenter.java index 6c58718f..1066477e 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/MainPresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/MainPresenter.java @@ -12,6 +12,7 @@ import com.hiroshi.cimoc.ui.fragment.FavoriteFragment; import com.hiroshi.cimoc.ui.fragment.HistoryFragment; import com.hiroshi.cimoc.ui.fragment.SettingsFragment; +import com.hiroshi.cimoc.ui.fragment.SourceFragment; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; @@ -28,6 +29,7 @@ public class MainPresenter extends BasePresenter { private CimocFragment mCimocFragment; private FavoriteFragment mFavoriteFragment; private HistoryFragment mHistoryFragment; + private SourceFragment mSourceFragment; private SettingsFragment mSettingsFragment; private AboutFragment mAboutFragment; private Fragment mCurrentFragment; @@ -56,11 +58,13 @@ public void onCreate() { .add(R.id.main_fragment_container, mCimocFragment) .add(R.id.main_fragment_container, mFavoriteFragment) .add(R.id.main_fragment_container, mHistoryFragment) + .add(R.id.main_fragment_container, mSourceFragment) .add(R.id.main_fragment_container, mSettingsFragment) .add(R.id.main_fragment_container, mAboutFragment) .hide(mCimocFragment) .hide(mFavoriteFragment) .hide(mHistoryFragment) + .hide(mSourceFragment) .hide(mSettingsFragment) .hide(mAboutFragment) .show(mCurrentFragment) @@ -73,6 +77,7 @@ private void initFragment() { mCimocFragment = new CimocFragment(); mFavoriteFragment = new FavoriteFragment(); mHistoryFragment = new HistoryFragment(); + mSourceFragment = new SourceFragment(); mSettingsFragment = new SettingsFragment(); mAboutFragment = new AboutFragment(); } @@ -89,6 +94,9 @@ public void transFragment() { case R.id.drawer_history: mCurrentFragment = mHistoryFragment; break; + case R.id.drawer_source: + mCurrentFragment = mSourceFragment; + break; case R.id.drawer_settings: mCurrentFragment = mSettingsFragment; break; diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/ReaderPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/ReaderPresenter.java index 3258634d..628c0518 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/ReaderPresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/ReaderPresenter.java @@ -1,8 +1,8 @@ package com.hiroshi.cimoc.presenter; import com.hiroshi.cimoc.R; -import com.hiroshi.cimoc.core.Kami; -import com.hiroshi.cimoc.core.base.Manga; +import com.hiroshi.cimoc.core.manager.SourceManager; +import com.hiroshi.cimoc.core.source.base.Manga; import com.hiroshi.cimoc.model.Chapter; import com.hiroshi.cimoc.model.EventMessage; import com.hiroshi.cimoc.ui.activity.ReaderActivity; @@ -37,7 +37,7 @@ public class ReaderPresenter extends BasePresenter { public ReaderPresenter(ReaderActivity activity, int source, String cid, String last, Integer page, Chapter[] array, int position) { mReaderActivity = activity; mPreloadAdapter = new PreloadAdapter(array, position); - mManga = Kami.getManga(source); + mManga = SourceManager.getManga(source); isShowNext = true; isShowPrev = true; count = 0; diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/ResultPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/ResultPresenter.java index 49d436bf..c0bf006c 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/ResultPresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/ResultPresenter.java @@ -1,7 +1,7 @@ package com.hiroshi.cimoc.presenter; -import com.hiroshi.cimoc.core.Kami; -import com.hiroshi.cimoc.core.base.Manga; +import com.hiroshi.cimoc.core.manager.SourceManager; +import com.hiroshi.cimoc.core.source.base.Manga; import com.hiroshi.cimoc.model.Comic; import com.hiroshi.cimoc.model.EventMessage; import com.hiroshi.cimoc.ui.activity.ResultActivity; @@ -26,7 +26,7 @@ public class ResultPresenter extends BasePresenter { public ResultPresenter(ResultActivity activity, int source, String keyword) { this.mResultActivity = activity; - this.mManga = Kami.getManga(source); + this.mManga = SourceManager.getManga(source); this.keyword = keyword; this.page = 0; this.isLoading = false; @@ -44,8 +44,8 @@ public void onDestroy() { mManga.cancel(); } - public void onScrolled(int dy, int last, int count) { - if (last >= count - 4 && dy > 0 && !isLoading) { + public void loadNext() { + if (!isLoading) { isLoading = true; mManga.search(keyword, ++page); } diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/SettingsPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/SettingsPresenter.java index ba1334b7..e213a655 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/SettingsPresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/SettingsPresenter.java @@ -1,7 +1,7 @@ package com.hiroshi.cimoc.presenter; import com.hiroshi.cimoc.R; -import com.hiroshi.cimoc.core.ComicManager; +import com.hiroshi.cimoc.core.manager.ComicManager; import com.hiroshi.cimoc.model.Comic; import com.hiroshi.cimoc.model.EventMessage; import com.hiroshi.cimoc.ui.fragment.SettingsFragment; @@ -27,14 +27,14 @@ public SettingsPresenter(SettingsFragment fragment) { } public void onCacheBtnClick() { - mSettingsFragment.showProgressDialog(R.string.settings_other_cache_doing); + mSettingsFragment.showProgressDialog(); FileUtils.deleteDir(mSettingsFragment.getActivity().getCacheDir()); mSettingsFragment.showSnackbar(R.string.settings_other_cache_success); mSettingsFragment.hideProgressDialog(); } public void onBackupBtnClick() { - mSettingsFragment.showProgressDialog(R.string.settings_backup_save_doing); + mSettingsFragment.showProgressDialog(); List list = mComicManager.listBackup(); if (BackupUtils.saveComic(list)) { String text = mSettingsFragment.getString(R.string.settings_backup_save_success) + list.size(); @@ -54,7 +54,7 @@ public String[] getFiles() { } public void onRestorePositiveBtnClick(String name) { - mSettingsFragment.showProgressDialog(R.string.settings_backup_restore_doing); + mSettingsFragment.showProgressDialog(); List list = BackupUtils.restoreComic(name); mComicManager.restoreFavorite(list); } diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/SourcePresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/SourcePresenter.java new file mode 100644 index 00000000..d00d3122 --- /dev/null +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/SourcePresenter.java @@ -0,0 +1,59 @@ +package com.hiroshi.cimoc.presenter; + +import com.hiroshi.cimoc.R; +import com.hiroshi.cimoc.core.manager.ComicManager; +import com.hiroshi.cimoc.core.manager.SourceManager; +import com.hiroshi.cimoc.model.EventMessage; +import com.hiroshi.cimoc.model.Source; +import com.hiroshi.cimoc.ui.fragment.SourceFragment; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.List; + +/** + * Created by Hiroshi on 2016/8/11. + */ +public class SourcePresenter extends BasePresenter { + + private SourceFragment mSourceFragment; + private SourceManager mSourceManager; + private ComicManager mComicManager; + + public SourcePresenter(SourceFragment fragment) { + mSourceFragment = fragment; + mSourceManager = SourceManager.getInstance(); + mComicManager = ComicManager.getInstance(); + } + + public List list() { + return mSourceManager.list(); + } + + public void add(int sid) { + if (mSourceManager.exist(sid)) { + mSourceFragment.showSnackbar(R.string.source_add_exist); + } else { + long id = mSourceManager.insert(sid); + mSourceFragment.addItem(new Source(id, sid, true)); + mSourceFragment.showSnackbar(R.string.source_add_success); + } + } + + public void update(Source source) { + mSourceManager.update(source); + } + + public void delete(Source source) { + mSourceManager.delete(source.getId()); + mComicManager.deleteBySource(source.getSid()); + EventBus.getDefault().post(new EventMessage(EventMessage.COMIC_DELETE, source.getSid())); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onEvent(EventMessage msg) { + } + +} diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/BaseActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/BaseActivity.java index 54af1c61..6a0f3290 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/BaseActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/BaseActivity.java @@ -1,19 +1,16 @@ package com.hiroshi.cimoc.ui.activity; -import android.content.Context; import android.content.pm.ActivityInfo; -import android.graphics.PixelFormat; import android.os.Bundle; import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.View; -import android.view.WindowManager; import com.hiroshi.cimoc.CimocApplication; import com.hiroshi.cimoc.R; import com.hiroshi.cimoc.presenter.BasePresenter; -import com.hiroshi.cimoc.utils.PreferenceMaster; +import com.hiroshi.cimoc.core.PreferenceMaster; import butterknife.ButterKnife; @@ -22,20 +19,15 @@ */ public abstract class BaseActivity extends AppCompatActivity { - protected View maskView; protected Toolbar mToolbar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - if (isPortrait()) { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); - } else { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); - } + initOrientation(); + initTheme(); setContentView(getLayoutRes()); ButterKnife.bind(this); - initNightly(); initToolbar(); initPresenter(); initView(); @@ -47,18 +39,21 @@ protected void onCreate(Bundle savedInstanceState) { @Override protected void onDestroy() { super.onDestroy(); - ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).removeViewImmediate(maskView); if (getPresenter() != null) { getPresenter().onDestroy(); } } - private void initNightly() { - maskView = new View(this); - ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).addView(maskView, getParams()); + protected void initOrientation() { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + } + + protected void initTheme() { boolean nightly = CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_NIGHTLY, false); if (nightly) { - maskView.setBackgroundColor(getResources().getColor(R.color.trans_black)); + setTheme(R.style.AppThemeDark); + } else { + setTheme(R.style.AppTheme); } } @@ -71,13 +66,6 @@ protected void initToolbar() { } } - protected WindowManager.LayoutParams getParams() { - return new WindowManager.LayoutParams( - WindowManager.LayoutParams.TYPE_APPLICATION, - WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, - PixelFormat.TRANSLUCENT); - } - protected View getLayoutView() { return null; } @@ -90,10 +78,6 @@ protected BasePresenter getPresenter() { return null; } - protected boolean isPortrait() { - return true; - } - protected void initPresenter() {} protected void initView() {} diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/MainActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/MainActivity.java index ac82c731..a244cf32 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/MainActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/MainActivity.java @@ -1,9 +1,11 @@ package com.hiroshi.cimoc.ui.activity; +import android.content.Intent; import android.support.design.widget.NavigationView; import android.support.v4.view.GravityCompat; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBarDrawerToggle; +import android.support.v7.app.AlertDialog; import android.view.MenuItem; import android.view.View; import android.widget.FrameLayout; @@ -13,7 +15,8 @@ import com.hiroshi.cimoc.R; import com.hiroshi.cimoc.presenter.BasePresenter; import com.hiroshi.cimoc.presenter.MainPresenter; -import com.hiroshi.cimoc.utils.PreferenceMaster; +import com.hiroshi.cimoc.core.PreferenceMaster; +import com.hiroshi.cimoc.utils.DialogFactory; import butterknife.BindView; @@ -27,6 +30,7 @@ public class MainActivity extends BaseActivity { @BindView(R.id.main_fragment_container) FrameLayout mFrameLayout; @BindView(R.id.main_progress_bar) ProgressBar mProgressBar; + private AlertDialog mProgressDialog; private MainPresenter mPresenter; private long mExitTime; @@ -42,9 +46,17 @@ public void onBackPressed() { } } + @Override + protected void onDestroy() { + super.onDestroy(); + mProgressDialog.dismiss(); + } + @Override protected void initView() { mExitTime = 0; + mProgressDialog = DialogFactory.buildCancelableFalseDialog(this); + mProgressDialog.setMessage(getString(R.string.dialog_doing)); ActionBarDrawerToggle drawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, mToolbar, 0, 0) { @Override @@ -94,6 +106,15 @@ protected BasePresenter getPresenter() { return mPresenter; } + public void restart() { + Intent intent = getIntent(); + overridePendingTransition(0, 0); + intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); + finish(); + overridePendingTransition(0, 0); + startActivity(intent); + } + public void closeDrawer() { mDrawerLayout.closeDrawer(GravityCompat.START); } @@ -106,12 +127,12 @@ public void setCheckedItem(int id) { mNavigationView.setCheckedItem(id); } - public void nightlyOn() { - maskView.setBackgroundColor(getResources().getColor(R.color.trans_black)); + public void showProgressDialog() { + mProgressDialog.show(); } - public void nightlyOff() { - maskView.setBackgroundColor(getResources().getColor(R.color.trans_white)); + public void hideProgressDialog() { + mProgressDialog.hide(); } public void showProgressBar() { diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/PageReaderActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/PageReaderActivity.java index 713ce8c1..800e6bb1 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/PageReaderActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/PageReaderActivity.java @@ -11,7 +11,7 @@ import com.hiroshi.cimoc.ui.custom.LimitedViewPager; import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeView; import com.hiroshi.cimoc.utils.ControllerBuilderFactory; -import com.hiroshi.cimoc.utils.PreferenceMaster; +import com.hiroshi.cimoc.core.PreferenceMaster; import org.adw.library.widgets.discreteseekbar.DiscreteSeekBar; diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java index 7d6afa85..0149b499 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java @@ -2,9 +2,7 @@ import android.content.Context; import android.content.Intent; -import android.graphics.PixelFormat; import android.view.View; -import android.view.WindowManager; import android.widget.TextView; import android.widget.Toast; @@ -15,7 +13,7 @@ import com.hiroshi.cimoc.presenter.BasePresenter; import com.hiroshi.cimoc.presenter.ReaderPresenter; import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeViewController.OnSingleTapListener; -import com.hiroshi.cimoc.utils.PreferenceMaster; +import com.hiroshi.cimoc.core.PreferenceMaster; import org.adw.library.widgets.discreteseekbar.DiscreteSeekBar; import org.adw.library.widgets.discreteseekbar.DiscreteSeekBar.OnProgressChangeListener; @@ -36,6 +34,7 @@ public abstract class ReaderActivity extends BaseActivity implements OnSingleTap @BindView(R.id.reader_back_layout) View mBackLayout; @BindView(R.id.reader_loading_layout) View mLoadingLayout; @BindView(R.id.reader_seek_bar) DiscreteSeekBar mSeekBar; + @BindView(R.id.reader_mask) View mNightMask; protected ReaderPresenter mPresenter; protected int source; @@ -44,6 +43,9 @@ public abstract class ReaderActivity extends BaseActivity implements OnSingleTap @Override protected void initView() { + if (CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_NIGHTLY, false)) { + mNightMask.setVisibility(View.VISIBLE); + } progress = max = 1; mSeekBar.setOnProgressChangeListener(this); } @@ -62,11 +64,8 @@ protected void onPause() { protected void initToolbar() {} @Override - protected WindowManager.LayoutParams getParams() { - return new WindowManager.LayoutParams( - WindowManager.LayoutParams.TYPE_APPLICATION, - WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_FULLSCREEN, - PixelFormat.TRANSLUCENT); + protected void initTheme() { + setTheme(R.style.ReaderTheme); } @Override diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/ResultActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/ResultActivity.java index 903773da..89f3cff0 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/ResultActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/ResultActivity.java @@ -10,6 +10,7 @@ import com.hiroshi.cimoc.R; import com.hiroshi.cimoc.model.Comic; +import com.hiroshi.cimoc.model.Source; import com.hiroshi.cimoc.presenter.BasePresenter; import com.hiroshi.cimoc.presenter.ResultPresenter; import com.hiroshi.cimoc.ui.adapter.BaseAdapter; @@ -36,7 +37,7 @@ public class ResultActivity extends BaseActivity { @Override protected void initPresenter() { String keyword = getIntent().getStringExtra(EXTRA_KEYWORD); - int source = getIntent().getIntExtra(EXTRA_SOURCE, 0); + int source = getIntent().getIntExtra(EXTRA_SOURCE, -1); mPresenter = new ResultPresenter(this, source, keyword); } @@ -61,7 +62,9 @@ protected void initView() { mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { - mPresenter.onScrolled(dy, mLayoutManager.findLastVisibleItemPosition(), mResultAdapter.getItemCount()); + if (mLayoutManager.findLastVisibleItemPosition() >= mResultAdapter.getItemCount() - 4 && dy > 0) { + mPresenter.loadNext(); + } } }); mResultAdapter.setOnItemClickListener(new BaseAdapter.OnItemClickListener() { @@ -112,10 +115,10 @@ public void addResultSet(List list) { public static final String EXTRA_KEYWORD = "a"; public static final String EXTRA_SOURCE = "b"; - public static Intent createIntent(Context context, String keyword, int source) { + public static Intent createIntent(Context context, String keyword, int sid) { Intent intent = new Intent(context, ResultActivity.class); intent.putExtra(EXTRA_KEYWORD, keyword); - intent.putExtra(EXTRA_SOURCE, source); + intent.putExtra(EXTRA_SOURCE, sid); return intent; } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/StreamReaderActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/StreamReaderActivity.java index ff73caa2..6d6fec4f 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/StreamReaderActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/StreamReaderActivity.java @@ -1,5 +1,6 @@ package com.hiroshi.cimoc.ui.activity; +import android.content.pm.ActivityInfo; import android.graphics.Point; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; @@ -9,7 +10,7 @@ import com.hiroshi.cimoc.ui.adapter.PictureStreamAdapter; import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeView; import com.hiroshi.cimoc.utils.ControllerBuilderFactory; -import com.hiroshi.cimoc.utils.PreferenceMaster; +import com.hiroshi.cimoc.core.PreferenceMaster; import org.adw.library.widgets.discreteseekbar.DiscreteSeekBar; @@ -38,9 +39,10 @@ protected void onPause() { @Override protected void initView() { super.initView(); + boolean split = CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_SPLIT, false); position = 0; mLayoutManager = new LinearLayoutManager(this); - mStreamAdapter = new PictureStreamAdapter(this, ControllerBuilderFactory.getControllerBuilder(source, this), this); + mStreamAdapter = new PictureStreamAdapter(this, ControllerBuilderFactory.getControllerBuilder(source, this), this, split); mRecyclerView.setItemAnimator(null); mRecyclerView.setLayoutManager(mLayoutManager); mRecyclerView.setAdapter(mStreamAdapter); @@ -114,9 +116,11 @@ protected int getLayoutRes() { } @Override - protected boolean isPortrait() { + protected void initOrientation() { int mode = CimocApplication.getPreferences().getInt(PreferenceMaster.PREF_MODE, PreferenceMaster.MODE_VERTICAL_STREAM); - return mode == PreferenceMaster.MODE_HORIZONTAL_STREAM; + if (mode == PreferenceMaster.MODE_VERTICAL_STREAM) { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); + } } @Override diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ComicAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ComicAdapter.java index 7f5b67ed..33654c05 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ComicAdapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ComicAdapter.java @@ -11,7 +11,7 @@ import com.facebook.drawee.backends.pipeline.PipelineDraweeControllerBuilder; import com.facebook.drawee.view.SimpleDraweeView; import com.hiroshi.cimoc.R; -import com.hiroshi.cimoc.core.Kami; +import com.hiroshi.cimoc.core.manager.SourceManager; import com.hiroshi.cimoc.model.MiniComic; import com.hiroshi.cimoc.utils.ControllerBuilderFactory; @@ -50,7 +50,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { MiniComic comic = mDataSet.get(position); ViewHolder viewHolder = (ViewHolder) holder; viewHolder.comicTitle.setText(comic.getTitle()); - viewHolder.comicSource.setText(Kami.getSourceTitle(comic.getSource())); + viewHolder.comicSource.setText(SourceManager.getTitle(comic.getSource())); PipelineDraweeControllerBuilder builder = ControllerBuilderFactory.getControllerBuilder(comic.getSource(), mContext); viewHolder.comicImage.setController(builder.setUri(comic.getCover()).build()); } @@ -77,6 +77,14 @@ public void update(MiniComic comic) { } } + public void removeBySource(int source) { + for (MiniComic comic : mDataSet) { + if (source == comic.getSource()) { + remove(comic); + } + } + } + public void removeById(long id) { for (MiniComic comic : mDataSet) { if (id == comic.getId()) { diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePageAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePageAdapter.java index 116841b0..2742accc 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePageAdapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePageAdapter.java @@ -28,6 +28,7 @@ public class PicturePageAdapter extends PagerAdapter { private LayoutInflater inflater; private OnSingleTapListener listener; private PipelineDraweeControllerBuilder builder; + private PhotoDraweeView item; private int left; private int right; @@ -44,6 +45,16 @@ public PicturePageAdapter(List images, LayoutInflater inflater, Pipeline this.right = MAX_COUNT / 2 + 1; } + @Override + public void setPrimaryItem(ViewGroup container, int position, Object object) { + super.setPrimaryItem(container, position, object); + item = (PhotoDraweeView) ((View) object).findViewById(R.id.picture_image_view); + } + + public PhotoDraweeView getPrimaryItem() { + return item; + } + public void setCurrent(int current) { this.current = current; } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PictureStreamAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PictureStreamAdapter.java index 49b4a6b1..add67868 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PictureStreamAdapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PictureStreamAdapter.java @@ -1,16 +1,23 @@ package com.hiroshi.cimoc.ui.adapter; import android.content.Context; +import android.graphics.Bitmap; import android.graphics.Rect; import android.graphics.drawable.Animatable; +import android.net.Uri; import android.support.v7.widget.RecyclerView; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; +import com.facebook.common.references.CloseableReference; import com.facebook.drawee.backends.pipeline.PipelineDraweeControllerBuilder; import com.facebook.drawee.controller.BaseControllerListener; +import com.facebook.imagepipeline.bitmaps.PlatformBitmapFactory; import com.facebook.imagepipeline.image.ImageInfo; +import com.facebook.imagepipeline.request.BasePostprocessor; +import com.facebook.imagepipeline.request.ImageRequest; +import com.facebook.imagepipeline.request.ImageRequestBuilder; import com.hiroshi.cimoc.R; import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeView; import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeViewController.OnSingleTapListener; @@ -26,11 +33,13 @@ public class PictureStreamAdapter extends BaseAdapter { private PipelineDraweeControllerBuilder builder; private OnSingleTapListener listener; + private boolean split; - public PictureStreamAdapter(Context context, PipelineDraweeControllerBuilder builder, OnSingleTapListener listener) { + public PictureStreamAdapter(Context context, PipelineDraweeControllerBuilder builder, OnSingleTapListener listener, boolean split) { super(context, new LinkedList()); this.builder = builder; this.listener = listener; + this.split = split; } public class ViewHolder extends BaseViewHolder { @@ -39,10 +48,6 @@ public class ViewHolder extends BaseViewHolder { public ViewHolder(View view) { super(view); } - - public boolean isEquals(PhotoDraweeView draweeView) { - return draweeView == photoView; - } } @Override @@ -78,7 +83,37 @@ public void onFinalImageSet(String id, ImageInfo imageInfo, Animatable animatabl } } }).setTapToRetryEnabled(true); - draweeView.setController(builder.setUri(mDataSet.get(position)).build()); + if (split) { + ImageRequest request = ImageRequestBuilder + .newBuilderWithSource(Uri.parse(mDataSet.get(position))) + .setPostprocessor(new SplitPostprocessor()) + .build(); + draweeView.setController(builder.setImageRequest(request).build()); + } else { + draweeView.setController(builder.setUri(mDataSet.get(position)).build()); + } + } + + class SplitPostprocessor extends BasePostprocessor { + @Override + public CloseableReference process(Bitmap sourceBitmap, PlatformBitmapFactory bitmapFactory) { + int width = sourceBitmap.getWidth(); + int height = sourceBitmap.getHeight(); + if (width > 1.2 * height) { + CloseableReference reference = bitmapFactory.createBitmap(width / 2, height * 2, Bitmap.Config.RGB_565); + try { + Bitmap bitmap = reference.get(); + int[] pixels = new int[width * height * 2]; + sourceBitmap.getPixels(pixels, 0, width, width / 2, 0, width / 2, height); + sourceBitmap.getPixels(pixels, width * height, width, 0, 0, width / 2, height); + bitmap.setPixels(pixels, 0, width, 0, 0, width / 2, height * 2); + return CloseableReference.cloneOrNull(reference); + } finally { + CloseableReference.closeSafely(reference); + } + } + return super.process(sourceBitmap, bitmapFactory); + } } @Override @@ -90,4 +125,5 @@ public void getItemOffsets(Rect outRect, View view, RecyclerView parent, Recycle } }; } + } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PreloadAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PreloadAdapter.java index 251467a2..4eaf699c 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PreloadAdapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PreloadAdapter.java @@ -28,15 +28,15 @@ public Chapter getNextChapter() { } public Chapter prevChapter() { - if (++index < prev) { - return array[index]; + if (index + 1 < prev) { + return array[++index]; } return null; } public Chapter nextChapter() { - if (--index > next) { - return array[index]; + if (index - 1 > next) { + return array[--index]; } return null; } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ResultAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ResultAdapter.java index ccaea3d3..a0f1b93f 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ResultAdapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ResultAdapter.java @@ -3,6 +3,7 @@ import android.content.Context; import android.graphics.Rect; import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.RecyclerView.ViewHolder; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; @@ -10,7 +11,7 @@ import com.facebook.drawee.backends.pipeline.PipelineDraweeControllerBuilder; import com.facebook.drawee.view.SimpleDraweeView; import com.hiroshi.cimoc.R; -import com.hiroshi.cimoc.core.Kami; +import com.hiroshi.cimoc.core.manager.SourceManager; import com.hiroshi.cimoc.model.Comic; import com.hiroshi.cimoc.utils.ControllerBuilderFactory; @@ -23,14 +24,14 @@ */ public class ResultAdapter extends BaseAdapter { - public class ViewHolder extends BaseViewHolder { + public class ResultViewHolder extends BaseViewHolder { @BindView(R.id.result_comic_image) SimpleDraweeView comicImage; @BindView(R.id.result_comic_title) TextView comicTitle; @BindView(R.id.result_comic_author) TextView comicAuthor; @BindView(R.id.result_comic_update) TextView comicUpdate; @BindView(R.id.result_comic_source) TextView comicSource; - public ViewHolder(View view) { + public ResultViewHolder(View view) { super(view); } } @@ -40,18 +41,18 @@ public ResultAdapter(Context context, List list) { } @Override - public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = mInflater.inflate(R.layout.item_result, parent, false); - return new ViewHolder(view); + return new ResultViewHolder(view); } @Override - public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + public void onBindViewHolder(ViewHolder holder, int position) { Comic comic = mDataSet.get(position); - ViewHolder viewHolder = (ViewHolder) holder; + ResultViewHolder viewHolder = (ResultViewHolder) holder; viewHolder.comicTitle.setText(comic.getTitle()); viewHolder.comicAuthor.setText(comic.getAuthor()); - viewHolder.comicSource.setText(Kami.getSourceTitle(comic.getSource())); + viewHolder.comicSource.setText(SourceManager.getTitle(comic.getSource())); viewHolder.comicUpdate.setText(comic.getUpdate()); PipelineDraweeControllerBuilder builder = ControllerBuilderFactory.getControllerBuilder(comic.getSource(), mContext); viewHolder.comicImage.setController(builder.setUri(comic.getCover()).build()); diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/SourceAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/SourceAdapter.java new file mode 100644 index 00000000..254d8036 --- /dev/null +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/SourceAdapter.java @@ -0,0 +1,79 @@ +package com.hiroshi.cimoc.ui.adapter; + +import android.content.Context; +import android.graphics.Rect; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.RecyclerView.ViewHolder; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CompoundButton; +import android.widget.Switch; +import android.widget.TextView; + +import com.hiroshi.cimoc.R; +import com.hiroshi.cimoc.core.manager.SourceManager; +import com.hiroshi.cimoc.model.Source; + +import java.util.List; + +import butterknife.BindView; + +/** + * Created by Hiroshi on 2016/8/11. + */ +public class SourceAdapter extends BaseAdapter { + + private OnItemCheckedListener mOnItemCheckedListener; + + public class SourceViewHolder extends BaseViewHolder { + @BindView(R.id.source_title) TextView sourceTitle; + @BindView(R.id.source_switch) Switch sourceSwitch; + + public SourceViewHolder(final View view) { + super(view); + sourceSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + mOnItemCheckedListener.onItemCheckedListener(isChecked, getAdapterPosition()); + } + }); + } + } + + public SourceAdapter(Context context, List list) { + super(context, list); + } + + @Override + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view = mInflater.inflate(R.layout.item_source, parent, false); + return new SourceViewHolder(view); + } + + @Override + public void onBindViewHolder(ViewHolder holder, int position) { + Source source = mDataSet.get(position); + SourceViewHolder viewHolder = (SourceViewHolder) holder; + viewHolder.sourceTitle.setText(SourceManager.getTitle(source.getSid())); + viewHolder.sourceSwitch.setChecked(source.getEnable()); + } + + @Override + public RecyclerView.ItemDecoration getItemDecoration() { + return new RecyclerView.ItemDecoration() { + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + outRect.set(10, 10, 10, 0); + } + }; + } + + public void setOnItemCheckedListener(OnItemCheckedListener listener) { + mOnItemCheckedListener = listener; + } + + public interface OnItemCheckedListener { + void onItemCheckedListener(boolean isChecked, int position); + } + +} diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/AboutFragment.java b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/AboutFragment.java index 33c2d815..7ac58f29 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/AboutFragment.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/AboutFragment.java @@ -4,9 +4,7 @@ import android.content.ClipboardManager; import android.content.Context; -import com.hiroshi.cimoc.CimocApplication; import com.hiroshi.cimoc.R; -import com.hiroshi.cimoc.utils.PreferenceMaster; import butterknife.OnClick; @@ -15,30 +13,12 @@ */ public class AboutFragment extends BaseFragment { - private boolean isEnable; - private int count; - @OnClick(R.id.about_support_btn) void onSupportClick() { ClipboardManager manager = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE); manager.setPrimaryClip(ClipData.newPlainText(null, getString(R.string.about_support_email))); showSnackbar(R.string.about_already_clip); } - @OnClick(R.id.about_resource_btn) void onResourceClick() { - if (++count > 9) { - isEnable = !isEnable; - CimocApplication.getPreferences().putBoolean(PreferenceMaster.PREF_EX, isEnable); - showSnackbar(isEnable ? R.string.about_turn_on : R.string.about_turn_off); - count = 0; - } - } - - @Override - protected void initView() { - isEnable = CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_EX, false); - count = 0; - } - @Override protected int getLayoutView() { return R.layout.fragment_about; diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/CimocFragment.java b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/CimocFragment.java index a8afd571..4c471f64 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/CimocFragment.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/CimocFragment.java @@ -10,11 +10,11 @@ import android.widget.EditText; import android.widget.TextView; -import com.hiroshi.cimoc.CimocApplication; import com.hiroshi.cimoc.R; +import com.hiroshi.cimoc.presenter.BasePresenter; +import com.hiroshi.cimoc.presenter.CimocPresenter; import com.hiroshi.cimoc.ui.activity.ResultActivity; import com.hiroshi.cimoc.utils.DialogFactory; -import com.hiroshi.cimoc.utils.PreferenceMaster; import butterknife.BindView; import butterknife.OnClick; @@ -29,21 +29,21 @@ public class CimocFragment extends BaseFragment { @BindView(R.id.main_keyword_input) EditText mEditText; @BindView(R.id.main_search_btn) FloatingActionButton mSearchBtn; - private int[] source; + private CimocPresenter mPresenter; + private int choice; - private int array; @OnClick(R.id.main_search_btn) void onClick() { String keyword = mEditText.getText().toString(); if (keyword.isEmpty()) { mInputLayout.setError(getString(R.string.cimoc_empty_error)); } else { - startActivity(ResultActivity.createIntent(getActivity(), keyword, source[choice])); + startActivity(ResultActivity.createIntent(getActivity(), keyword, mPresenter.getSid(choice))); } } @OnLongClick(R.id.main_search_btn) boolean onLongClick() { - DialogFactory.buildSingleChoiceDialog(getActivity(), R.string.cimoc_select_source, array, choice, + DialogFactory.buildSingleChoiceDialog(getActivity(), R.string.cimoc_select_source, mPresenter.getItems(), choice, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { @@ -76,9 +76,6 @@ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { } }); choice = 0; - boolean enable = CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_EX, false); - array = enable ? R.array.ex_source_items : R.array.source_items; - source = getResources().getIntArray(R.array.source_id_items); } @Override @@ -86,4 +83,14 @@ protected int getLayoutView() { return R.layout.fragment_cimoc; } + @Override + protected void initPresenter() { + mPresenter = new CimocPresenter(this); + } + + @Override + protected BasePresenter getPresenter() { + return mPresenter; + } + } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/FavoriteFragment.java b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/FavoriteFragment.java index 1baa6e8e..01b2ef9e 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/FavoriteFragment.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/FavoriteFragment.java @@ -4,6 +4,7 @@ import android.app.NotificationManager; import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; import android.os.AsyncTask; import android.os.Build; import android.support.v7.widget.GridLayoutManager; @@ -11,11 +12,12 @@ import android.view.View; import com.hiroshi.cimoc.R; -import com.hiroshi.cimoc.core.Kami; -import com.hiroshi.cimoc.core.base.Manga; +import com.hiroshi.cimoc.core.manager.SourceManager; +import com.hiroshi.cimoc.core.source.base.Manga; import com.hiroshi.cimoc.model.MiniComic; import com.hiroshi.cimoc.presenter.BasePresenter; import com.hiroshi.cimoc.presenter.FavoritePresenter; +import com.hiroshi.cimoc.ui.activity.DetailActivity; import com.hiroshi.cimoc.ui.adapter.BaseAdapter; import com.hiroshi.cimoc.ui.adapter.FavoriteAdapter; import com.hiroshi.cimoc.utils.DialogFactory; @@ -50,7 +52,8 @@ protected void initView() { @Override public void onItemClick(View view, int position) { MiniComic comic = mFavoriteAdapter.cancelNew(position); - mPresenter.onItemClick(comic); + Intent intent = DetailActivity.createIntent(getActivity(), comic.getId(), comic.getSource(), comic.getCid()); + startActivity(intent); } }); mFavoriteAdapter.setOnItemLongClickListener(new BaseAdapter.OnItemLongClickListener() { @@ -60,7 +63,7 @@ public void onItemLongClick(View view, final int position) { new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - mPresenter.onPositiveClick(mFavoriteAdapter.getItem(position)); + mPresenter.deleteComic(mFavoriteAdapter.getItem(position)); mFavoriteAdapter.remove(position); } }).show(); @@ -111,6 +114,10 @@ public void removeItem(long id) { mFavoriteAdapter.removeById(id); } + public void removeItems(int source) { + mFavoriteAdapter.removeBySource(source); + } + public void addItems(List list) { mFavoriteAdapter.addAll(0, list); } @@ -133,10 +140,10 @@ protected List doInBackground(MiniComic... params) { int count = 1; for (MiniComic comic : params) { int source = comic.getSource(); - if (source == Kami.SOURCE_EHENTAI) { + if (source >= 100) { continue; } - Manga manga = Kami.getManga(source); + Manga manga = SourceManager.getManga(source); String update = manga.check(comic.getCid()); if (update != null && !comic.getUpdate().equals(update)) { comic.setUpdate(update); diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/HistoryFragment.java b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/HistoryFragment.java index 8728e387..59e1a0e2 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/HistoryFragment.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/HistoryFragment.java @@ -1,7 +1,7 @@ package com.hiroshi.cimoc.ui.fragment; import android.content.DialogInterface; -import android.support.v7.app.AlertDialog; +import android.content.Intent; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; @@ -10,6 +10,8 @@ import com.hiroshi.cimoc.model.MiniComic; import com.hiroshi.cimoc.presenter.BasePresenter; import com.hiroshi.cimoc.presenter.HistoryPresenter; +import com.hiroshi.cimoc.ui.activity.DetailActivity; +import com.hiroshi.cimoc.ui.activity.MainActivity; import com.hiroshi.cimoc.ui.adapter.BaseAdapter; import com.hiroshi.cimoc.ui.adapter.ComicAdapter; import com.hiroshi.cimoc.utils.DialogFactory; @@ -26,16 +28,16 @@ public class HistoryFragment extends BaseFragment { private ComicAdapter mComicAdapter; private HistoryPresenter mPresenter; - private AlertDialog mProgressDialog; @Override protected void initView() { - mProgressDialog = DialogFactory.buildCancelableFalseDialog(getActivity()); mComicAdapter = new ComicAdapter(getActivity(), mPresenter.getComic()); mComicAdapter.setOnItemClickListener(new BaseAdapter.OnItemClickListener() { @Override public void onItemClick(View view, int position) { - mPresenter.onItemClick(mComicAdapter.getItem(position)); + MiniComic comic = mComicAdapter.getItem(position); + Intent intent = DetailActivity.createIntent(getActivity(), comic.getId(), comic.getSource(), comic.getCid()); + startActivity(intent); } }); mComicAdapter.setOnItemLongClickListener(new BaseAdapter.OnItemLongClickListener() { @@ -45,7 +47,7 @@ public void onItemLongClick(View view, final int position) { new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - mPresenter.onPositiveClick(mComicAdapter.getItem(position)); + mPresenter.deleteHistory(mComicAdapter.getItem(position)); mComicAdapter.remove(position); } }).show(); @@ -62,9 +64,8 @@ public void onClick(DialogInterface dialog, int which) { new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - mProgressDialog.setMessage("正在删除..."); - mProgressDialog.show(); - mPresenter.onHistoryClearClick(); + ((MainActivity) getActivity()).showProgressDialog(); + mPresenter.clearHistory(); } }).show(); } @@ -93,7 +94,11 @@ public void clearItem() { } public void hideProgressDialog() { - mProgressDialog.hide(); + ((MainActivity) getActivity()).hideProgressDialog(); + } + + public void removeItems(int source) { + mComicAdapter.removeBySource(source); } } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SettingsFragment.java b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SettingsFragment.java index 221119cb..e3c401dc 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SettingsFragment.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SettingsFragment.java @@ -2,17 +2,16 @@ import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; -import android.support.v7.app.AlertDialog; import android.widget.CheckBox; import android.widget.TextView; import com.hiroshi.cimoc.CimocApplication; import com.hiroshi.cimoc.R; +import com.hiroshi.cimoc.core.PreferenceMaster; import com.hiroshi.cimoc.presenter.BasePresenter; import com.hiroshi.cimoc.presenter.SettingsPresenter; import com.hiroshi.cimoc.ui.activity.MainActivity; import com.hiroshi.cimoc.utils.DialogFactory; -import com.hiroshi.cimoc.utils.PreferenceMaster; import butterknife.BindView; import butterknife.OnClick; @@ -24,17 +23,18 @@ public class SettingsFragment extends BaseFragment { @BindView(R.id.settings_other_home_summary) TextView mHomeSummary; @BindView(R.id.settings_reader_mode_summary) TextView mModeSummary; + @BindView(R.id.settings_reader_split_checkbox) CheckBox mSplitBox; @BindView(R.id.settings_reader_volume_checkbox) CheckBox mVolumeBox; @BindView(R.id.settings_other_nightly_checkbox) CheckBox mNightlyBox; private SettingsPresenter mPresenter; private PreferenceMaster mPreference; - private AlertDialog mProgressDialog; private int mBackupChoice; private int mHomeChoice; private int mModeChoice; private int mTempChoice; + private boolean mSplitChoice; private boolean mVolumeChoice; private boolean mNightlyChoice; @@ -48,9 +48,9 @@ public void onClick(DialogInterface dialog, int which) { @Override protected void initView() { mPreference = CimocApplication.getPreferences(); - mProgressDialog = DialogFactory.buildCancelableFalseDialog(getActivity()); mHomeChoice = mPreference.getInt(PreferenceMaster.PREF_HOME, PreferenceMaster.HOME_CIMOC); mModeChoice = mPreference.getInt(PreferenceMaster.PREF_MODE, PreferenceMaster.MODE_HORIZONTAL_PAGE); + mSplitChoice = mPreference.getBoolean(PreferenceMaster.PREF_SPLIT, false); mVolumeChoice = mPreference.getBoolean(PreferenceMaster.PREF_VOLUME, false); mNightlyChoice = mPreference.getBoolean(PreferenceMaster.PREF_NIGHTLY, false); mHomeSummary.setText(getResources().getStringArray(R.array.home_items)[mHomeChoice]); @@ -62,12 +62,14 @@ protected void initView() { @OnClick(R.id.settings_other_nightly_btn) void onNightlyBtnClick() { mNightlyChoice = !mNightlyChoice; mNightlyBox.setChecked(mNightlyChoice); - if (mNightlyChoice) { - ((MainActivity) getActivity()).nightlyOn(); - } else { - ((MainActivity) getActivity()).nightlyOff(); - } mPreference.putBoolean(PreferenceMaster.PREF_NIGHTLY, mNightlyChoice); + ((MainActivity) getActivity()).restart(); + } + + @OnClick(R.id.settings_reader_split_btn) void onSplitBtnClick() { + mSplitChoice = !mSplitChoice; + mSplitBox.setChecked(mSplitChoice); + mPreference.putBoolean(PreferenceMaster.PREF_SPLIT, mSplitChoice); } @OnClick(R.id.settings_reader_volume_btn) void onVolumeBtnClick() { @@ -140,13 +142,12 @@ protected int getLayoutView() { return R.layout.fragment_settings; } - public void showProgressDialog(int resId) { - mProgressDialog.setMessage(getString(resId)); - mProgressDialog.show(); + public void showProgressDialog() { + ((MainActivity) getActivity()).showProgressDialog(); } public void hideProgressDialog() { - mProgressDialog.hide(); + ((MainActivity) getActivity()).hideProgressDialog(); } } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SourceFragment.java b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SourceFragment.java new file mode 100644 index 00000000..457722c8 --- /dev/null +++ b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SourceFragment.java @@ -0,0 +1,101 @@ +package com.hiroshi.cimoc.ui.fragment; + +import android.content.DialogInterface; +import android.support.v7.app.AlertDialog; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.widget.EditText; + +import com.hiroshi.cimoc.R; +import com.hiroshi.cimoc.core.manager.SourceManager; +import com.hiroshi.cimoc.model.Source; +import com.hiroshi.cimoc.presenter.BasePresenter; +import com.hiroshi.cimoc.presenter.SourcePresenter; +import com.hiroshi.cimoc.ui.adapter.BaseAdapter; +import com.hiroshi.cimoc.ui.adapter.SourceAdapter; +import com.hiroshi.cimoc.utils.DialogFactory; + +import butterknife.BindView; +import butterknife.OnClick; + +/** + * Created by Hiroshi on 2016/8/11. + */ +public class SourceFragment extends BaseFragment { + + @BindView(R.id.source_recycler_view) RecyclerView mRecyclerView; + + private SourceAdapter mSourceAdapter; + private SourcePresenter mPresenter; + + @Override + protected void initView() { + mSourceAdapter = new SourceAdapter(getActivity(), mPresenter.list()); + mSourceAdapter.setOnItemLongClickListener(new BaseAdapter.OnItemLongClickListener() { + @Override + public void onItemLongClick(View view, final int position) { + DialogFactory.buildPositiveDialog(getActivity(), R.string.dialog_confirm, R.string.source_delete_confirm, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + mPresenter.delete(mSourceAdapter.getItem(position)); + mSourceAdapter.remove(position); + } + }).show(); + } + }); + mSourceAdapter.setOnItemCheckedListener(new SourceAdapter.OnItemCheckedListener() { + @Override + public void onItemCheckedListener(boolean isChecked, int position) { + Source source = mSourceAdapter.getItem(position); + source.setEnable(isChecked); + mPresenter.update(source); + } + }); + mRecyclerView.setItemAnimator(null); + mRecyclerView.setLayoutManager(new GridLayoutManager(getActivity(), 2)); + mRecyclerView.setAdapter(mSourceAdapter); + mRecyclerView.addItemDecoration(mSourceAdapter.getItemDecoration()); + } + + @OnClick(R.id.source_add_btn) void onSourceAddClick() { + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + View view = getActivity().getLayoutInflater().inflate(R.layout.dialog_add_source, null); + final EditText editText = (EditText) view.findViewById(R.id.source_edit_text); + builder.setTitle(R.string.source_add); + builder.setView(view); + builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + int sid = SourceManager.getId(editText.getText().toString()); + if (sid == -1) { + showSnackbar(R.string.source_add_error); + } else { + mPresenter.add(sid); + } + } + }); + builder.show(); + } + + @Override + protected BasePresenter getPresenter() { + return mPresenter; + } + + @Override + protected void initPresenter() { + mPresenter = new SourcePresenter(this); + } + + @Override + protected int getLayoutView() { + return R.layout.fragment_source; + } + + public void addItem(Source source) { + mSourceAdapter.add(source); + } + +} diff --git a/app/src/main/java/com/hiroshi/cimoc/utils/ControllerBuilderFactory.java b/app/src/main/java/com/hiroshi/cimoc/utils/ControllerBuilderFactory.java index 45c67285..ffaae41a 100644 --- a/app/src/main/java/com/hiroshi/cimoc/utils/ControllerBuilderFactory.java +++ b/app/src/main/java/com/hiroshi/cimoc/utils/ControllerBuilderFactory.java @@ -9,7 +9,7 @@ import com.facebook.imagepipeline.backends.okhttp3.OkHttpImagePipelineConfigFactory; import com.facebook.imagepipeline.core.ImagePipelineConfig; import com.facebook.imagepipeline.core.ImagePipelineFactory; -import com.hiroshi.cimoc.core.Kami; +import com.hiroshi.cimoc.core.manager.SourceManager; import java.io.IOException; @@ -28,7 +28,7 @@ public class ControllerBuilderFactory { public static PipelineDraweeControllerBuilder getControllerBuilder(int source, Context context) { if (builderArray.get(source) == null) { ImagePipelineFactory factory; - if (source == Kami.SOURCE_EHENTAI) { + if (source == SourceManager.SOURCE_EXHENTAI) { factory = buildFactory(context.getApplicationContext(), source, "igneous=583e748d60dc007822213a471d8e71dcba801b6a55cd0ffe04953e8adb63f294d4b60f303d9182b4276281ac883cec4c48a669db0b6c4914da78073945f49b12583e748d60dc007822213a471d8e71dcba801b6a55cd0ffe04953e8adb63f294d4b60f303d9182b4276281ac883cec4c48a669db0b6c4914da78073945f49b12"); } else { factory = buildFactory(context.getApplicationContext(), source, null); @@ -42,7 +42,7 @@ private static ImagePipelineFactory buildFactory(Context context, final int sour OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { - String referer = Kami.getReferer(source); + String referer = getReferer(source); Request.Builder request = chain.request().newBuilder(); request.addHeader("Referer", referer); if (cookie != null) { @@ -57,4 +57,24 @@ public Response intercept(Chain chain) throws IOException { return new ImagePipelineFactory(config); } + private static String getReferer(int id) { + switch (id) { + default: + case SourceManager.SOURCE_IKANMAN: + return "http://m.ikanman.com"; + case SourceManager.SOURCE_DMZJ: + return "http://m.dmzj.com/"; + case SourceManager.SOURCE_HHAAZZ: + return "http://hhaazz.com"; + case SourceManager.SOURCE_CCTUKU: + return "http://m.tuku.cc"; + case SourceManager.SOURCE_U17: + return "http://www.u17.com"; + case SourceManager.SOURCE_EHENTAI: + return "http://lofi.e-hentai.org"; + case SourceManager.SOURCE_EXHENTAI: + return "https://exhentai.org"; + } + } + } diff --git a/app/src/main/java/com/hiroshi/cimoc/utils/Decryption.java b/app/src/main/java/com/hiroshi/cimoc/utils/DecryptionUtils.java similarity index 97% rename from app/src/main/java/com/hiroshi/cimoc/utils/Decryption.java rename to app/src/main/java/com/hiroshi/cimoc/utils/DecryptionUtils.java index 5b20c35b..1f2fc867 100644 --- a/app/src/main/java/com/hiroshi/cimoc/utils/Decryption.java +++ b/app/src/main/java/com/hiroshi/cimoc/utils/DecryptionUtils.java @@ -14,7 +14,7 @@ /** * Created by Hiroshi on 2016/7/8. */ -public class Decryption { +public class DecryptionUtils { public static String desDecrypt(String keyString, String cipherString) throws Exception { byte[] cipherBytes = Base64.decode(cipherString, Base64.DEFAULT); diff --git a/app/src/main/java/com/hiroshi/cimoc/utils/DialogFactory.java b/app/src/main/java/com/hiroshi/cimoc/utils/DialogFactory.java index 08206492..5bc9af4a 100644 --- a/app/src/main/java/com/hiroshi/cimoc/utils/DialogFactory.java +++ b/app/src/main/java/com/hiroshi/cimoc/utils/DialogFactory.java @@ -12,7 +12,7 @@ public class DialogFactory { public static AlertDialog buildPositiveDialog(Context context, int titleId, int messageId, OnClickListener listener) { - AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.AppTheme_Dialog_Alert); + AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle(titleId); builder.setMessage(messageId); builder.setPositiveButton(R.string.dialog_positive, listener); @@ -27,7 +27,7 @@ public static AlertDialog buildSingleChoiceDialog(Context context, int titleId, public static AlertDialog buildSingleChoiceDialog(Context context, int titleId, String[] array, int choice, OnClickListener listener, OnClickListener positive) { - AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.AppTheme_Dialog_Alert); + AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle(titleId); builder.setSingleChoiceItems(array, choice, listener); if (positive != null) { @@ -37,7 +37,7 @@ public static AlertDialog buildSingleChoiceDialog(Context context, int titleId, } public static AlertDialog buildCancelableFalseDialog(Context context) { - return new AlertDialog.Builder(context, R.style.AppTheme_Dialog_Alert).setCancelable(false).create(); + return new AlertDialog.Builder(context).setCancelable(false).create(); } } diff --git a/app/src/main/res/color/button_chapter_color.xml b/app/src/main/res/color/button_chapter_color.xml index e89f0aa6..77f397fb 100644 --- a/app/src/main/res/color/button_chapter_color.xml +++ b/app/src/main/res/color/button_chapter_color.xml @@ -1,5 +1,5 @@ - + \ No newline at end of file diff --git a/app/src/main/res/color/button_chapter_color_dark.xml b/app/src/main/res/color/button_chapter_color_dark.xml new file mode 100644 index 00000000..e0f31ed9 --- /dev/null +++ b/app/src/main/res/color/button_chapter_color_dark.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-hdpi/ic_add_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_add_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..694179bd46b685e55da1b4dde2575bde0b2bfd64 GIT binary patch literal 127 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K;o2QFoh{y5d1PRu~4CX)Hf7s8+ zA**4&;-NiFVdQ&MBb@07vc`*Z=?k literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/button_chapter_selector.xml b/app/src/main/res/drawable/button_chapter_selector.xml index 5faa0030..254bb53e 100644 --- a/app/src/main/res/drawable/button_chapter_selector.xml +++ b/app/src/main/res/drawable/button_chapter_selector.xml @@ -11,28 +11,28 @@ - + - + - + diff --git a/app/src/main/res/drawable/button_chapter_selector_dark.xml b/app/src/main/res/drawable/button_chapter_selector_dark.xml new file mode 100644 index 00000000..e4a8f93d --- /dev/null +++ b/app/src/main/res/drawable/button_chapter_selector_dark.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/progress_trans.xml b/app/src/main/res/drawable/progress_trans.xml index d2119801..1b28fcaa 100644 --- a/app/src/main/res/drawable/progress_trans.xml +++ b/app/src/main/res/drawable/progress_trans.xml @@ -11,10 +11,10 @@ android:thicknessRatio="10" android:useLevel="false" > + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_detail.xml b/app/src/main/res/layout/activity_detail.xml index 1f10f701..5dd2f086 100644 --- a/app/src/main/res/layout/activity_detail.xml +++ b/app/src/main/res/layout/activity_detail.xml @@ -4,8 +4,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:layout_width="match_parent" - android:layout_height="match_parent" - android:background="@color/white"> + android:layout_height="match_parent"> + android:indeterminateDrawable="?attr/progressDrawable"/> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 235d7686..f8e04d2c 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -9,7 +9,7 @@ android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="@color/white"> + android:background="?android:attr/colorBackground"> + android:indeterminateDrawable="?attr/progressDrawable"/> + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_stream_reader.xml b/app/src/main/res/layout/activity_stream_reader.xml index 0a17fb3f..e7dc88f3 100644 --- a/app/src/main/res/layout/activity_stream_reader.xml +++ b/app/src/main/res/layout/activity_stream_reader.xml @@ -40,6 +40,7 @@ android:textColor="@color/white" android:textSize="12sp"/> + \ No newline at end of file diff --git a/app/src/main/res/layout/activtiy_result.xml b/app/src/main/res/layout/activtiy_result.xml index cc8f3b0c..b6fa2e1e 100644 --- a/app/src/main/res/layout/activtiy_result.xml +++ b/app/src/main/res/layout/activtiy_result.xml @@ -4,19 +4,17 @@ android:id="@+id/result_layout" android:orientation="vertical" android:layout_width="match_parent" - android:layout_height="match_parent" - android:background="@color/white"> + android:layout_height="match_parent"> + android:layout_height="match_parent"/> + android:indeterminateDrawable="?attr/progressDrawable"/> \ No newline at end of file diff --git a/app/src/main/res/layout/custom_mask.xml b/app/src/main/res/layout/custom_mask.xml new file mode 100644 index 00000000..0e936591 --- /dev/null +++ b/app/src/main/res/layout/custom_mask.xml @@ -0,0 +1,10 @@ + + \ No newline at end of file diff --git a/app/src/main/res/layout/custom_seek_bar.xml b/app/src/main/res/layout/custom_seek_bar.xml index 493fb443..8a8df503 100644 --- a/app/src/main/res/layout/custom_seek_bar.xml +++ b/app/src/main/res/layout/custom_seek_bar.xml @@ -17,9 +17,9 @@ app:dsb_min="1" app:dsb_indicatorPopupEnabled="true" app:dsb_trackColor="@color/white" - app:dsb_rippleColor="@color/colorAccent" - app:dsb_progressColor="@color/colorAccent" - app:dsb_indicatorColor="@color/colorAccent" + app:dsb_rippleColor="?attr/colorAccent" + app:dsb_progressColor="?attr/colorAccent" + app:dsb_indicatorColor="?attr/colorAccent" app:dsb_indicatorTextAppearance="@color/white" app:dsb_trackHeight="4dp" app:dsb_thumbSize="12dp"/> diff --git a/app/src/main/res/layout/custom_toolbar.xml b/app/src/main/res/layout/custom_toolbar.xml index 3252a5ad..8091f72a 100644 --- a/app/src/main/res/layout/custom_toolbar.xml +++ b/app/src/main/res/layout/custom_toolbar.xml @@ -3,6 +3,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/custom_toolbar" android:layout_width="match_parent" - android:layout_height="?attr/actionBarSize" + android:layout_height="wrap_content" android:background="?attr/colorPrimary" + android:fitsSystemWindows="true" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/> \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_add_source.xml b/app/src/main/res/layout/dialog_add_source.xml new file mode 100644 index 00000000..9d5900b6 --- /dev/null +++ b/app/src/main/res/layout/dialog_add_source.xml @@ -0,0 +1,17 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_about.xml b/app/src/main/res/layout/fragment_about.xml index 0ba87d0b..1e0640ce 100644 --- a/app/src/main/res/layout/fragment_about.xml +++ b/app/src/main/res/layout/fragment_about.xml @@ -7,7 +7,7 @@ + android:background="?attr/colorPrimary"> + android:paddingRight="4dp" + android:clipChildren="false" + android:clipToPadding="false"/> + android:paddingRight="4dp" + android:clipChildren="false" + android:clipToPadding="false"/> + android:id="@+id/history_clear_btn" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="16dp" + android:layout_gravity="bottom|end" + android:src="@drawable/ic_delete_white_24dp" + app:layout_behavior="com.hiroshi.cimoc.ui.custom.ScrollAwareFABBehavior"/> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml index 633eb3bd..e5dc54eb 100644 --- a/app/src/main/res/layout/fragment_settings.xml +++ b/app/src/main/res/layout/fragment_settings.xml @@ -36,7 +36,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="16sp" - android:textColor="@color/black" + android:textColor="?android:attr/textColorPrimary" android:text="@string/settings_backup_save"/> @@ -98,7 +96,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="16sp" - android:textColor="@color/black" + android:textColor="?android:attr/textColorPrimary" android:text="@string/settings_reader_mode"/> + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_chapter.xml b/app/src/main/res/layout/item_chapter.xml index 15f43ae8..8e577d61 100644 --- a/app/src/main/res/layout/item_chapter.xml +++ b/app/src/main/res/layout/item_chapter.xml @@ -7,11 +7,11 @@ android:paddingLeft="6dp" android:paddingRight="6dp" android:gravity="center" - android:background="@drawable/button_chapter_selector" + android:background="?attr/backgroundChapter" android:textSize="12sp" android:singleLine="true" android:ellipsize="end" - android:textColor="@color/button_chapter_color" + android:textColor="?attr/colorChapterText" android:clickable="true"/> diff --git a/app/src/main/res/layout/item_comic.xml b/app/src/main/res/layout/item_comic.xml index a4a91d4e..bc7eb3cf 100644 --- a/app/src/main/res/layout/item_comic.xml +++ b/app/src/main/res/layout/item_comic.xml @@ -29,14 +29,14 @@ android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:padding="6dp" - android:background="#AFFFFFFF"> + android:background="?attr/colorBackgroundTrans"> + android:layout_height="match_parent"> + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/drawer_menu.xml b/app/src/main/res/menu/drawer_menu.xml index 27684fc0..35de75ac 100644 --- a/app/src/main/res/menu/drawer_menu.xml +++ b/app/src/main/res/menu/drawer_menu.xml @@ -11,6 +11,9 @@ +

diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png index 5a4b2fe0258a1e38bbc4d980f0181cd46dd862fd..6ec096db97dcf639344e0579d6b6b758836e3728 100644 GIT binary patch literal 508 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAjKY=BRQE09*4_L)fZ|NsBvPyb9f z^|N%}kB>k8MQ-?}KljV(>%XqP{%gDVtM{s}JMaCTd-2!fPk)<_{7B#ao$uB@A)p0( zB|(0{3?I^>ltRz%-E8~3J)h_A`qmBx21W-@7srr@!*4Hl=QTM9um)_&*xJAIcOB!u z|LN0iW-Vs%*}TM5t$MO&T4YgL1K=c&Om<*q$VkF9MjvKWm7Od9`qW;#f*`-UmcEY$2| z+0VrJvsy#Qa!E}@Q046f%NcTi#+dMb{3jwMEq5k2ujsh&`~5lfb~!!87Z}RtiCw(k z?&lzW!fWkg9+8H|ru22~n^S6Hnmis_pFHRAJT_ndK7W#+(qj{aD>pa~9{q8ClAqkI zn}0rVzIa;v_pj)x0Fa0FH+|Dy@Yr;Vc6r?F*)=&{bGPk0`@ArELhS7;f9m%!Y^pl` UN59A^4;ab}p00i_>zopr0EbiVv;Y7A literal 2653 zcmV-j3ZnIiP)Fab;;3{Wsf3Zw}~ASD5t#D^>!3w+@N%d+roU7cMWNcLyTj!4Nc-~OlFw{PG6 z_P1|$-}}VG=CoSDm3|RmIDiIb2M3Uc-NOOI0py*7P!(-moKj!!}&T^UG+v8%n*Ws1tW#E0Q$bDx-34>nL`Iea8O%J!nC7gbPTH^ zvz3R0l1AEgEinnJTxr`@*#ma}KTZKz)(`mg@QiK`9&N_9OtbCXufX)<*<1LFQg9I?* zkDuJXB#V_no?!uMd!mpTvIjoAE*LEWDAe_|eWb7&=jD^3GY4aO z`E?i}`tcS%=AMHBC_-3;D~aQ%scj}djMJ3EWS{iRVR^`j&P1nKf~3-#$2^@!KfFhP zNWkfqQVw5!2f8d`q?BrDfXlTg#KmYZ$H2XSQMCxCUYnb>0hCBA%X_XmwpBb zuZu=2ueDF@cf4qk7PE$(f|%D05`#X{vIGFHUwN|F%Yr|mk;(=rVE9t80z5Tikq-NdJx%> zYn}Q^J5@N}Ity80JKV;|uHS?`Ivb#l!oZBP@+nYAG;Z}KD-S7ZEjq0Jee4`7$;S!# zj6U^;o0niy-L8J;H6TFmMXW?d;4$iy6HDq~fnZPo9gLZWN&a8E0Yow$1*!zvf1&mi zj>OIZ;|NUKa}F*)o#T*gJz7n&5)aFzgj7U{s#$HR?1{m&@|$jL{=5g&P4F1@Z^bez zKgGqizTkOekXj{!m}f-J{VZ&6+&n07h|rn1sZjY8<67IZSXz04_9Fo0s}g8{on%7z zj0H#ai?OwSD+-kH6fCQi!H&i^u)Apkp7Fhi+}M|BU&1&?aXn4nYuJe0P3vh>g17{q z%coKhCYBbX$!xoSk+jdX#4#8lY=F)bgvn)vP9M5HbSqv9*-f(~ZI%Gm`Sr^nnV<$& z6)DvBq?HxnzA1dr09}etMU=Q2XAE<(re-hg=gYL?2h}J#0kV$g4Cz=^vmaun6Gf^R z3Ye<63f=If@*<|2)(aRDrk7uXwkMI+7b>IR$L~aGmkQ|>S6G>~Pq!Rz*S|~K#z^vU zQa)qIyTGBiUw{@!KSg$A7D!@HSyJoKnYmi}okD?NfexSOR$xp0Hrgaa51lZ%eV2BQ zM!NPAU0+v#T$w`p6e#78@(oyD^AG&Xuo%So7ph{ZzExFw@$c5TZUDU>nTcOZ^H9(} z9t-ZCqitWsPe6?LE>0WfBFny5gI?)@oOEVT4*nwBj82OLN$R29ZyW$+H*CTl`-w$P zkRnwyL_8yA-M$1(x6S#x){jwZ(e6U^|HMy3tXPXvhIv?9^D#yWs`0fVmG+ygxrI7Y zq}yEI4Bv=XgFkZfeHBR|bX%w2zKGK9L; zE5)wMiZvnIu`cXg`{@HrDbGi(G1?8F!}=xIbkBCj2;w*4hEi!?&4;HFsW>Zt4oZm{ zpBrXlb&QfB*&Zn{h*-==c6WG?F8GUG)bz z)0*KNz;TMX0wm?@QJ}QlgL*S4Hzotm_+LR`=UBX`{nDu?SyF&J`SWy)r_^`QVfBNQ z-;A3B*tE5N3-;=4k7`nUd2RF##1?^Y$Q*B3hz+%Sh7J(vK|Vtv+lV;V-sM(DDt=#i z46VKH5XWL?Ak{Y?o9}Hyu6_mWM&d}eW7~{rW!F(@lsnb!id=y?(i5odiNJH^-@6S% zwg|auOw^P>XAhgCNWQ}{`K&%3#qmW)Z##qejkugRjz%4Nmwmbwc-wx`vLWR0E#~Mn z&Hp@-B{t)0j8XL19cr0A>?}wi?STF@x325MwqkYYPS(54qQLzSGDhU;m%H^L{)oKe zLWK=zxA@_x{$;m!ADeAsB{!+l7cxD#(=ErT2ZZ(gzukzAK?5{YFrE~74j>OJ$pORx z0Tqhio4Wh??%{tH&o zCCBp>*Xb}@WE-$F=wZmzF*f-ZPO7>b?bZOqiOO*yVG?Wj{IljI*l14!UstFQDjppWsE?9Y94kpNqIg)MX9!?dG7C5MPH_0i>;*z6CdLHQsOoUgD4 z%X=&8u=pTZZA$}RPDnwdh&@F#ui_kj=o*jN0mtz7sFketko;V-Uw6?-1Y^-{~W^)H?D@%a9$*ZSk~{kh)zozePdxA#k`^}iy5`2YX_0d!JMQvg8b*k%9#0Fg;V zK~zY`?b5*t!yphv(Y$M7)Tr(Me{EF?Es}++K!OiJH)qCyS$>`p4Q7G~ZVuLAU;v|) zQ4n~^atwEHc(u@4v6mwOLGqOJU_(D3u`7RHMwK2tupLP8ju>#t>;c~cDVwbhBU?Y>-6+Zmd00000 LNkvXXu0mjf1!8#T delta 1723 zcmV;s21NOm0>BNB8Gi-<00374`G)`i28T&RK~!i%?U{LS6lEI5e{(RCYZ7uzNCLSb zAczOcVTB_Ff`P5&lFdR?TtoykLNtgGFOCpYb_GRI4nra-T_X@#4wpe>Q!EvPlp-Jy z7803++?gYpgJd$()^wGlR!E$bHO0C${ZH3?{r2;|&+~l!^?%#*N#eJ*3H*)^iI>1_ zcF*g;Z8iX}1OKxQgv;s~?t9i%pL4A(w~WCm_>$sZiVTPA+LiWXs%`Py>wB7Dna(v{ zXN%%u`*0EzSBO_sy2ft`N=}+n370jvoui_CFg3QgE_!u4g))NkSr@eu31Anbm>vFP zR_{b-59PCjDSyZ%4jh7n4nfIVjVsvJvW(J!BN(8lMi9Uz^x=!vDP-O#BscOIGD3EX z$vYh~YHiWXtUSuJp#5&=*wnC+9lB-i6S&<|!`=MehuB@EJQe44z*EY)i|cj3U8Ot~ z_y6xelHwBgtBxR-*ig&sIodXr6XyGIzNz~ww0vV7<$o!0-NNnBf%LwGyc)R*UunAw zEWddXxeXgwrGAM=!*-B*rJTCX0d6JpL{PT`rUw@DX8)%+Z63p#`VE-uDn3h?%zop8 zA_29$j@UkxoUx{OqAs^FZ%H6Yahc-yKXSbzjs@Cc4E9hFaIo?`273tgozZS5@O0oU z3A`1(kbjA)qs;q$KNoJ^bITgm_gjuq+QEw2_Xv=-ayW4u1uaitarm(^A{S>T`a$zj z=7;WNnD2Q`m{NJFdKVTUK*UQ{USNfKJ>vtu#Ow%QYf~0Gbx*r;DJ3__4qwZ|p@mo- zejGGTXM6K9Zgj@}qMj}UoWTD~m_(6o0qYuG>wi|jf|v&pkg!0z2d872fnzB*jpQEx zaxPhiG0gA0*p*&uPo%~cL#paH*)>}zG0sCRujLO^)8;Tdq@18 z7r9*g6rFJOEbAk)n4&t&v}>g_*?%L6l-IC7VG_mqhxl95E4&!7O1wV1N<)iXE#BY1 z&-X|X(AwgAoOAFjd3c^)xL|#5yeMbeUp;{FpzB=f||4isu#KYgrJsjZv2`G1T`QAI8n0!hbr1|Cm#m zsL~K7Yhq5-VXoVfxXY)UqPW@ON_MR60aVgfaatcT&Tt9xBa2%uqfWNj>Ri$S4gQ6@Iv2#RWXKGCgGPHliVgGem$Y#pF_rw5B^2owiPtwqJxP+Xf>~9^#NW;r zqw}r)z}1s9+as8!+Q+l%*MEppR`Q*7IC%|g_{uWQrS5%xr7R2I$O!+_wAzC>V3t^3LBhe-85r%s%nL3Qd;cE~XIENgnSa0|!P^Oz>s{m3 z9kG-c=aTBLVYuHnuJI0sf&$%Q5|vln&T-m&AEzwiyKw84zyyB{86kyY=i}T5a5i<$ z4;7O`MNYrf;s%Fvyc0PGjWflTAulqEPYn14QQH~TUb`2v%822{)N{^C zyM*f96P%hg&A&}i&?#bi>wR^^}FxjmnoY9t*CR+uqG0lXm*$S5JY=hUD*= zOW2=XQkA-)%eBMu&Jy++#a(kk4gSwO$6@1osCD5{?&o-18JGhz`C%FlDpK(kMc3Zdq)r(W}g&Nk@@$Hsmyz(ce)qi56#_!_3*ZX{rZ+$8? zt07X-IV(A6%f$~f_OJRq&U@mG9%@mMvylS;04g1Ab(33b_rF3)e5-L;flvSd z+@hnd`UqjWV?%<-{QNzoX#)^RF>s<;X@nS1?+U3)*le2Z3%S5nx zH2W}r&b!2Pn(_xu76cUmdiE6vJCS*dU*Ea|g^)-H_7`cprE(_;2Gq_9l&f(Ty-khX zrWDRp z_`^)9k&LX6RvvOIz15yb3iBksFSIc>BUP2p_^FNmG!udL5-^I}jDAO5lVwr=go*7v zJ>{!K7PBB$i9|j3ax=wc&K+W(F^jo|ydsoNZrMq4`BtY{*eHQjT1SY8Sr|GJ2S+3t zq?s=F%*dUi7kT@mf0B5sUVyA+lAo1QO1}@}F`ey`0iik=E$FX>3--^xd&=grQlpu8 z^l4S>(fx56hiS!J#L@_s%`gUTb^W-kibkbAiO5&r-rhYU`~9A(k!!rUJ+JO)4?x6% zU5UQ0JPy0M&0)#|wN<|c^JL%ab1+8Qoori{bnll>9Xd`HW4XlLIxm zPBes%h>}1l^(natlF96&I42%Wh*z}}-r`)GsH-G<*x^XcfLQ1s!vU^Uquo@nc!k+hb_ZgOXQQ}2MJ1!@4W z{1wlE=Py%_|%-L6Ng<3Zx)%PL<0i$fKKSz}{Y$*jsYx4{g{Ylm;Dnscojx zu_9lkI|xa{+UcHfxm|xHObQ@G21Wsh!xv24QF#f1{S_{zX9GrE8HMP7!iA+|7OfCn z1mP5cEUvnn@T6LxcL-(i_g@TvM=Rw_RS(Rbs_W}7tWQUNZO$k@Ls+OW?*rm!jnq>A zWbd|yP)EJo`f%eor`=_RVKZYIG}(L6ss09I0G6cnp+cFKtuosfx_QMXo(Bx^qECLt zJZS~KzGkBF}REA6}SgUsut%VSmQ%ELbTCrb&fC2rHi(k(V= zkMLY#FG6IbBw2zrgC6;@-W>fzI`c27^wt#BA3_XhKBVMNDF6+mt77`ExNyEKrjEH) zogNrcADy4{7iO#88mG|rRNuZsI_}DI2;7leqe34psrt&?d{>Unstps8h4(AX)lBYcgPruU_4%MZm~og>Nzx4LmQ13 zctMsHtZXT}xWcMZdn+^(*Fnyp90 zf0nr#;KTIZ{ zjXHTbkVq1GTbd`a+3%B@SKL0FpvLBr3Z~OGU|K=F-i4wTJ8VyNR9o6Rv|DPVi331n zdBWN-eJ->X2NR++M!hbd-!jWC(-w{IJF8Z@-G$i2MQ7Km&(*tG@9+$czX9hDNSM0# ze;L$`XH=A~r2m^iVoYI3Cj*j$L|W!7ba*;<<>gtm?a^gPbx`-?EzqY&B9xW{;`P)| znn=DgiuVU@J8vOMqUFHs7^1NL3S$>aRreE5>$>4ZPs&;+vecJmKj>h)3~xS+(OY-snV*TH};X8E*6) zrDbfu725E69nYO^Yj66HQms2#PgPEHT;~dL<~FlA!NlKsKQ*?^P#n=(I-d0BlxX}Y z&U2ItO;1p^X-yNL`FA&Wy7qKd1o*Ot$~}cG#^sv_i-ogQWwIgzP^tT2Xt3zo?5nf3R$t717I z`+Wn62!c)q00{89A3*xU^NBUFTCP{CT+FEg+$7mWnPQT@46aaPSk@vVM)V)(Q@jpv z>%MPDJ?{)#4V{`HXSC1tgDqWe-CxZ6Fm6@HD%l66g0^JL%9SMc55LN8vWg2&Y2ul?-LELS z+-0|TO)G88l~Tf)Y`Vl$T@Olw&Y9hC`fvzIqx>`KXb!^gnSkEJwq!YIG+61PQCNY? zI+;lC;O#2C*>M3w|9GG58H?ZEW&Qx>w@~X$Uc@d_{Pso;q$qd8vTS$|J|bRGFr3O> z@lVG=6lmroX=~=*mttl(H@X}e`s3!#Kw;}rQFF!}mD@3LbRJo$*X%@Q%a z7k9ImWJ{7eY077#EqfQy0@N3srYHtMtC$YenjRo>r+lih%R30Ux_M72S@eKKH?uCo z=mD4zUk){!qcMGd+6!7ywD&OwDMYLe20Q)H7k@!kS&jN+J3!V+R*} zR@U(zyI`tULYG^<0eIruD&2_|O~owQbKA-Rw?jD8G{+x5+3@q|b01fP2}O3nmCnZ+ zl?ME7|0E`6xd(leo^4^-oO$A(?9PZoKAtL+WBM3Nqr3RRo3h{Z30Sr;*p3Xw?xU`l zK5~5e75jULWe@5!IzETGsl#vBIM`j-HG!h{d{f1^ky;8jWx2TXUO7z1noKZbRk0ei z{8d-VYTfdwk>^RD$mf9PtUsSYG?Z*UK*pJ#LAmYeN)d8WeMwaxsoUxPvhXya^9nPO(>~&F%_&w z3KMiEE!1sz`Z~LO#@^4spP{X7R%g37zQYW!&WeN(=}eF8w%ktl*7RiR8DcJid!~Fs z%dYj=gZj2G62$W8Muu4aOd{mxrq5-%stid=xQnIg4XD)8Jr@4|76(#yyG+Nx7A zn#N`_ae4E^i!?e#1*H2XI7X{9W7udtx1ypUpUew|P{a#e941%LHLL}a!K|t=k)^o* z@cNT?WoWZM46>0g8U6qxv}S|wro!u8NIYvgEx|IV779{hPb$BWGOraahGs=rbcn9+G z{PL>U>~@$Nn-%LcvAIu)Vr-L#=PtazOnj|hS{rfGU3*Rn)%+`xA5|Ws6L7rN-)W%4 zmft0{r7sZIk|BFBYPzU}5#mql9{fF@*RFGuga*95|Em!i;i34kMR%SeVsH{egcv=P zQs)T!XvYOB-eBW(<+xYpC+jEUoHbC3wI|Rf!^Lha(=OU*0$mcir9;# z9~`jkhbY2oV~ea$!=CPIuQ$4|ud{f6q7!opj+$R|rqOfms7Fk?Y~Jhc1PcijecANC zg8!&PtHuUPB#iMSeVFf0AA)#E#l8(aEzX@Cr}dTb(|}fNA(7SJhNk`D^~Q@r#I2kG z36TQKO*bZvRx5=T;1jm8u9vlX#tp>@Q1qCjVz-V)Mb+87aa?M zpoMX}r73~S8;|81^MSr6k-6D+WdFxa0eX?SVDF~j?*tYE3+Tw)nIAixC|@1U<(9|`4!+}v$M^`o#~8wy z8xof%qleBv_wQk>V8g+E@0tdKL})@d>1-X52W79NGPr-Qd-jOJLvkwD6MWWK`!GUY zbv7nGrkcO+1A$#?IiJqj&EIhX`5R(Kbq_S04%^oI_8wldxv&`O)BK3M<;;~t)3$#q zUkm2*x$<-jc#n?h^fB5nr;Zmx7o2G46YJ;KfBo2=uu{LTC0!+O_Gazkb}fO1^`CmWR^F4*9EreO`_4(lO!*jOzhFUj2_N84XYn~)R*NvoZ}k2VFoI` z==aB8d2S)+uoV>>qnp5`%Fo`>i}XdbwBOfLNrZ1(BSnB;S7vaNB0y2rE9Dt6-L-l$!yQu#GCsB^( diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index aee5a3be1267134e15006efa53b6c32e5f3c6cda..3520d8a862b381324f2e04bc1d71d5cf4b5630a3 100644 GIT binary patch literal 967 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=asqrpT!FOWw9n+B|Ns9_IQ27f z!?)v4|9t%MPk-*0(tSU?SADfz{PpVVzmGrtU48x6&U?Spw|{Rw@?-ABUrPQ@mjUe) zE(!7rX1H{CX2-WldTe{wDm^SqkMgtSIj87S&cML*-P6S}q~g}w+c(2*8wfN!G)YNZ zZg4HDvi^VhnyoHH4JkPmQ!VHG%v-bT#?NF=M!g#XP8^E+&%RFF-5&F;eD~w8bG9=- z*|vM{rQ+Z0pKix#-a077CtlsRq3iGA^HmNE{?nV@CCGlC-t_N))w{Z=3)7l3I-1S} z3bZvDh_ozJ;9*VF;Ba=7;5rn5Md-qmm(q$XuSHl=V>wuZEt_{}_(?HOoAfy1fXgw3 zt75@tRCg)5ST=`*&dC;O*w`%9RO7hPeOnK&;#yV)+j&}wC#0_Il38}ZsQ2&mGUs&) zC!~(V`d5j~{bH;7{LYfaFD11Pi}rjy#{Zb}+rE1l)kT>BH4c}xz2EX3(tTf`^H*=p zF%{j%R>dNd3#;9%&g{*(@<^dv|3`*Y$jL*K^So+fPOR@1Ug_Vvs6%DG{FJma3XYyt zKMgk8na=&SBm3v31^3?OnXGtQ5naLj{!YM+>+9}%d|vmFU%;)-qM&|LoWzkgyb~7~ zEYGbvTv{Q0#(w&bHBr_D!mIwA^kV+guCVgan{6LgDYa~U@Y3L?^A3dwnHIlDov@=T z{I&IK=1dp3;eLfNq%2DD=cz?u9s=Idla{Z3lvw5ZW7T?g$?x0h0|Y|eFOOMy(=j!| zEb~-}MUAq@ao>kCR|S1;a$=tCSNGC<@eenFE9*Mu|5|c(w)B-H@0(Zg$=|Qq#BpW8 zH1?^j%2nsA!+w9fqoABCXuM!c&;RI~f!1lW;>1kjMW(3buF^_pt=&`RAwSV`rv=BZ z&(a@2s`n}`b@30o|p1e|Cj4WW5P)SIhAOL|M8#vK2g?udegi_*?N7}y|#y> zfVR$e(37j`(dr_-QSK@SCz*?CqaMp>J^rvf{f4=dY#^62Sbf6=wV}{5I;d0->xrtp^U$Ybh-yh+iVLq_7g< z$tm>~L7iJo`8&GebQR~Hy_=a+Jty?v#@I={+&4x31g%U?W?oM6oK8*(C8c<#(x1iC zxTFFV1cPgFh4SL4`p|}=x4?iLh*SS4k2}EiZF~4Dh6Ka2^T`}Y4zknB{vJ3$l!pQ5 z;Ikpn1<>)D^7|y(kkJ3}k(ol2n6v{kx2u5Wzjp+<3{@pOOlKOy$;-tQ7e)#?v^nhv1crN#BR8# zk|KE?)&wMe3t1iVM_V5i?$TMxWBlFZ6^*4--s0zl)j~x<{kdUOma>#arTGvP?gIH4 zN!FPBR}!{0%GdC@5%c$6sDahpMdJBr$~&W5hY5c_Fpt_KZRssYXXIRh$1%-V>rmv# z>>fCU@BZy*>iZ>QR$(w$c%ExhnWTtf`)hU5Xk_kd>U+vjb|p2TQbI-P5KAQW_r*JC zlW;?N)BPmP>uAFiNO$Pw@MF8~7E6tL1v?=h6H)H<+kf*OmUqQ77Wx6qei3AD6=c*i zk^5rAjHx50X}U;QZ%zIJowT2RYwD8};leJgE$j~!s7$)3@&3?DLuj&rI6V|&aR-`fDoCS#onc6-wdR#pX|8BP6M)IULAyUzt;nnyE z?0@Yj;sA{w=&hvqOo1*LDG!hs3TamardOS&$(DRhP>tV4KIn zEAJyY!s>=^;dHCE`hw98}znMrPhaf+IID)={|F`feVV84zC&q zDvDt6&`gZ+d@vpywgr>qWk?`0n1u?aJhQGLhNTuA7-g>pfCYmPI8 zMjHXWDtwy*F-9@LEEM|R2c2OC(uN~#Ur;mB8O)PBsoMeFj~lWH&mZ&gPPqWGa158o z%{B#XODUb_t4!naAIds@z2d9^$c1~a1+~2KjHisEc{~N4zw?a*6%8!qK=x+MA#krN z?Db$2EAV5Ic6j4Q|H*7n&6vrnRb9r|+5vnVDJ@X$J4jembNvF8F&JiH zx3HTRUEA>|*^j{K(h)_X)V*<2G|OwZ0@-i@W>qVjHrw>@1wc&DIWVYj9w#Q3Zm_<{ zQZNRSi=Tv+<=;T-UXOzM$EHoDr?JX6%Rp^AptHWCuPxgb2n@uiU=U%2R)N4h3+K#I zcdWYlr>DV-C88WDX>rj~^ck&AraKq}vd^5OcOz?&7Q;LYZz3;tcE$7wc6v8MjZ!Fk z*^Ce(BKgO^ha2iki==L?Zl*k@z{-|0TWrP&F$g~7YI13NcFkG(@IA-yqg|c5G+W++ z7O?qM@OuRLBgL`X zFW|dtpU((PvTME;inJbR-J(P?dH23FLaH)!j5gSSGFXk}+wSSkEPQTM+I~M{&X>wWj}lm?DFt^6Igw^rhszizLES$oAimj z;W?3TkuIF4L0=3NJsP|o@|NdE*=+#`SGWlM@?x_u z@5ccb?TKS7OfLrLo47tg!!w}P(zY$Z=Usm(5~Qz^d|kzRYa#dBjjRSSXDN(^>BD*^ zJsF!BEhwwngbJ;cubE9xw2|CCRyC7}cKRz89`1@ayLixL>f)J_X=$UPlvCM5>V5&< zO`5)ro6x~4kJ|xw(ftMIIB8iaVQv$B5<-5i?Ow7C&s9O72S-HK3{EcVOU>$_2EG4o zgqo}vbLYzOlSt@vtn3R!D`U8Q9FHZf!4>f$2visw4v`A{*;>xWry3ct7Yn{d_7M*BqHq4HWeZd3Dn*| z=DA4wCb}nFbUKJcY3@5<^NY2s15{2G%#0PhTp5V89vWYtXM1Nel~|-~YF}8|^&PJO z{hCWq;~HCr<-)b?SrJ}C7I$!L&dG1jqq_8Oy_We!R_3w;%7`s{Qt2?xqLz8=1@A%# zkhFcYb41blv(miCk)*p=9tEF@mtskh4U6$Djzktn$xroo8FUJx}vm z``BLweslxNnbL!N9c&A?Y2lQm$S9Xm6+HoEeci(~t`41OvqtJ_6|#ulhai?m1IMeu zleJ+%^^IQHC2=s4Sm?%J;jN;&;?x{&qItlg99dOhb7CzPS}`AUVi8Q9)T$KXqj{fQ z`H*1D8999G!{kQv|VVqJ|3|^|5HdURhY9IbH%Cb!I$R)x-{$~7*u)~tE z>{8?s0$^&osS5%O7K}J62HAY`69f}ZyRG>6 z>!1|U!1&MxaY`6*@$b7^k>x%*+Bc>PPT2V$=Amy)?YQUxix(q{o`6tvi6fx_C0gmaf^gFqp_*Qc_6k3MGoihG3(3j?AU3H?{OKZ>h~|O4%C|9ie6Bp0oJbXK&Ibz3=n-?u!pV z)I4>6ZHiY-_;D^Tz=b16F)+GM#iH0E$q!$1zYE>q9qQR)4uw4W`qZ81f2+r9UkvB|(c>U3GgxB(8d1e7yujHS+7h~h)s7*gfw3`q5z&dTf`lv!ZTv$T zuB{!74~-TLzrj946S#8y@|BJ#dDFC`{XYWr^f=Yp+1+}d5A^Z{F?+b(Q>cy-^PwJt zNg?|1`PsCMn`7KFCd2P~;AQP!_l0PBI=taV2~7c(enbQf01Ikpy<_M8LuVyMsb!t5 z+d-4)KRQw3fP^>$nW%hw=V5sDDWij_Zn9*gq6P*Rw|N|Ar{*WG%KXu!0p2$s-+Fg8 zIvS^=$xP-FWqu)~SwwSpteJh2+_Ypgmwb)}IwZpDz`VF8H%a3MNwbs7q~&@_T5men z)7j!YS}pLe;?BnFdYPfBHa6&)$E;W0zx|o?fN{)XATSfvSmsf_u4iD@C`D%TlfW@0 zJsh-SsxL7)rYs+KIR2YQ&me{`deAlg+10GM@by#JN!)GBFt7Wg25-K=jxk8swwC>E zC9`*%UMbl?$HQw+@s>R50h zGCPH28v8JDrf%xTz!Mov^q*9FQ}guOE6Q&YYLxA?js5dY>cu*+2lh$^o^1+lrKiY= z5?k;Hu8)x>Bu?>c0>y$)biEBVDc1}*Mf;Dd~zYiU@ueQpv ze$E{1SWlU|Bp*q@6-c6h9a$x8bCFxa6C$Ln^C}1u4;0w$2*zI7;TJinEDEvnmqdj< zO)@zF*eC&XSCu?1d24fY0`5h(XXwPF$0za@KgWF(beuQIZmtGTHSF2AMYXNx;p(YU5*Ww<7Ac)u7SFR#P~qm165dI-OG*7`|Y)Yw|6K*?rVP~l`X zps*dAK;o@+Zo|r+Gsg{?6zffapSlq2>nJ-!%RCo?rVbEY!jaF$+5p7*VJlbwAE zy*mbl9WN?k-!uCA?(fgZA?<%E{|xjg%hySDUFwtIMzyxmu>WyrrvHjdiW^1p+ht`g zBei#^Hke1zmBK&CpUS|tb=F1&y-S}H*|};|xO!_3E|Af(u&H_TYR|Xn%`^z8<2_#S<3Z zX+Rm#pT03FG!+L$Y2*{*wGwmI>&b+4zb^VJ^e5upr~cQxrD{P%=ciA+at0>dNloB< z=#33iAg|$<36w^G@F#t58b6cUNh?yRrj{n9t#RPIqGy(hqT~fS6aX@po)xTS%|Z{= z(U!5lldpStBU~P6A)%qRp(_l$ydV@@8|LM8fRa9P(pksFv6UB`juQa*at3U$cpon) zvYRCQ?ArwP(P){btOG4qzqTM=pI+BOj-duGUSt?+vM6h)k54NTrn^_ioLYlz9yxhd zajRH)g+q)0;{B^bgkj4yymV}A8Nn(?TyMSUc#RUmGsVGOZH?kSb+cq$ZQI^O-@iK? zfT=h>J{Nk<6^5+%l+o%aDE$f>KHm*H70(@;nluVQ-VeGgG~fShq5$Q%^?zNc7IX`7m8ALwz6T#3Lv6v;(kDSc<_g46R~I~occ z8IBfjY&(Ur#__^gyV>erqlKt(V@$l`b~oqu#$;&i|paY&Kh-s*w{D9)1~i)hzg3fh0_! zV`WRpc0(h+?=j?Vs&(@=N|uPUC5P=xg}B7x#+Ui(Q+}AoCH@WXYSnc8g9bDeM+ztBs|S8nL95L&jls>QMZR#p~-VNcmjpN~!=; zSRgy68=SA3$&s@1fVkalK?n^LE^nlm<;HszIn%uzHbUA2O61r6j_pYo2mgaA+Hs2c zfl}IR%^(v4~kS5lD2oxt0-2hzL3~ zqo`H1n7Tg~Jg6;N+L!Z$LxVWav_wg>`q{IsQi>ZVT&LIU8`+O5fikbJfWn`{&+)c6 z__Ci5izv=MP38LVS<}T}&9a{Gh40@a+CZq9#(V+Y&`+FaJlS{_MS8O+WNCAQN&6RNj?n?ch?}utI}GT@rMRDnP>qBq2h4vyOrkDC zBPbqwIPHvPnq`-IRae6}f;hLdysB|oSqNhaPDM{ITGL`772;&5a6KA1IL1ocgfZ1a zt*9y|lEnPlnCdR6cyuA)&y~oSaMN`MZQ@nY1w%un4Rg$uMmg8LG`7&CBBbm_ar`m^ zzlG@U-E*?a<)muq;b%f_?{5wgopyj(1#UV!3jgSB!#|FLAvoPcB^dg>i|d$0iV;4t zVBy<;v905mUe55@mKfz#{Awn@%xiA{?yuYUbNIpZvTS|ra4V@$A)fH{KhJdbQCs)9 zq=~+oH->L>1ziL&5QHw=E+V0wCqvEM<^f)fPQDgzb5=|!4mRT8=8BEb1nbrODs~ora z)pN-&@UQp5wPgmBas~&sKHx?CU}K;mjJTmG{KO;I!qtp~d%lRw+%@};_wxKl;J_Xo zD^_ks*?y^o$sNu&Uxc`i-H;MLf#F-9vA5ErSep%=Td8$57p(lP#5;}ouP(G33w+2# z(pCq>JrXqw>Qd0pjjH*qsH`X)HCp3+u5R zz8Gi9>!<9Aqo*J^HJe;sXb;u5m%B+IyEY3DMUu?^@ss`?k$6P_Kw@cQ1CE^_#tKg9h9IOLp8tP}_J3<9(`3zs!7RirWR zI#s#Hl$X^GP-gLGh#eMlSJpRxJo7#O?+VTx`i1xxHv_Oy1NtASRvyYN_7S)ZReM4w z9Hb{dq99<;&dp1YGm2)dT*pS~C8B_Hqbaf5=0XwsNKF=baBV&OzsbLU%eKnMQQ$vg zCJG85a>P$ZQM0s!vn_7EOI4F1#zb95_c#dpmEC4K9R^W_qf|hk#g*LRC zLh-QC-vd)qw@~wW9H!jbp3zXolvcnwrIQXuqyc&x81fVO=JrzEp%y8nBpF`1dj$L7 z1#ARmC(OvCqy^ib-zkL~Q@qv(AU}TpPJVO5(L01q?wzjQPm;MGmq#zZ<1?R`NQX8l z@07#wlfNy0n@5gXvxHp%Xewq>jXQuB1x7hm*cvLUrF{6ryKHB$C{3`9a)C2rPB4f@ zyO?&JV4MS?02ox8ztGRsMv5OWJh(Ijri00lpl7%!?dJ;c1==*kY@^`XPxvWtsJ_ES zVuNzM&`(Ew?89NSJ*uz6%n^7B)ojO9-GafQD9w7qE`aD3E3slihJ?t^;3^{3cMYx8 zkyktazd@TBgW<5JT}k=OAd&}Tf099kK%c;x?$@K0l#S7R;4-**o)S|)OOsWi1Y%bQ zd&hf9g+DO#g>#P&*e5rsS&vh<`QryZDBNlBi&u@w-x&QHb*0BmwFhu-Cj5+^85N*3F0U56J(}D#Egw?&3f6E)YG{x4*;ssVom9hBNFf z76;nY-7h%t%J|b|hk_!_G;jQJOkXV9f?9o({?^jiwWh(2g8V1`iwrJSR|PB?UML-N zScyj~_uVQ{?9_DM;i`x}Scq3I^9;B1bSJICImWqMx*7&cv zM;z(nKS-_gbVWfdF~)cobS%?m-b&6gEa)GYVUOgR?-%|a8*R3LtHrAj5la_Ppk7C@ z_NN^%4Nj_jLCt0?<-~{emE*%SpOU?i^is5={k{9&PZ#3LQ0{?|%)Oa@lNn(4syQ|I{9olxSswC`G;>_MIW*2X$VfyJ4o60#fbI=>fg0v zL2HxBWzmWgY$WXoC2Zpc{nR-P?L4S)_zZFthjYyARhY9y_kuVjGhcV?DOGD6qwE>3 z?x4=CxkM(7(X{U?Wkf7x+JyW;`2)2WP2=$ulw}_^ke5$$IHHy!JW=?xWzU z8T!fMslKc0W2Y#{f$Z2S*Vzo9?GY>w)1=@jh&mn;sJwI>0N;GV+yK#KY~6)u3<_Hua7_dE#3E{`N)r*_kO2u|33HPuN;L{=YSTA zl?3?(Gn~2f`|IN+(?k!agqOLQsw=T0vX`}$QF0|Se^r;B4q#jQ724fzfk2)JA{ z^lLiMDBw{2e{s;FC6T*lKiV%{let6?XcmKv?YdMh^{qO&;p?C4%1rgGeP?RpySi%2 zhp(Y|pQZkL2EUR$_bj$Eydv9c&BNTlN5c2gRBiMhtk){!EN0cQhSc@tgUI+tj#MeXh^Bn-ssZYb+~&Gtu=_SkDgo2d?v# zgq&v{Y`D#QDgOKKd~u6k8{)VOrksdq zNcQbbTXsnC_A7_E+ZR@BRka8ZeB#A0U0#m!hD}4n_WevB`ixYpQ`Z!1@R{kf-9*C}#%ASAT@npk)ZN)WfINrEf zY-U)P!eVIkdHN(t)rR=cW(HfP>D%wxy!~Ovcc;I?!Nh~%_1E9MYxv|8`>s1HNU1dJ z`Vqs}eEYaZadaFoeev+!uYiIh%fcNN?74J&^_m;WCtd8{ef(9& zc2o21RGts7d(F-F)EzDjXme7^&Q;0J`crvR+G|aIhMEhjR3M}13|`R;7uJvjvycUX zq5+LJ0~*~z99Yww(Ig+N-n;v_qe5GwhRvUxB&9M}=XdoXQd&~Sg^sTIvQOG3a^3O{ z2Btd#0WJ)Tc^n$xoF*dZ&>+p!#qp!`o9UX}Lb+ADwG5YSU+1!;FR1SAsV^_zEDXuH zeEsd(JBfSNSZ;Y#u=n7$Y~Pa8{&@>i4SyZ=uHMH2%<&J_+d1kkuQ=bm<}IiI@O1Ta JS?83{1OP2bL9YM+ literal 5730 zcmd^@*E<~Cx5sA~j82H?gqIM#L??P3MvoGV5_R<6hv;3DBw9pIw9)e_A$sq9l!#7- zXhTLjei!FII5+2rtefxito_}4t@Vl5)lnlQq9+0X0Hhk~%K8sy*MAlm|6$i( zffE1#G~61>3WfoeXp6uAqq(O0HwEgfgfUSR_T|fd?AwtHm z3&<6v!1#Wsbx++r+)kDD%&X&XPcGTm5%s8v`a2@5N>O3FMS@IK1Yu$0U(-NNz%}B3R>YdUYj6wKB=15H+s~+^ zoR%iu*taQf#BcxDO`fL+*K9-Xjx_$c3EsXY(_FVILiVkfr{%AK`qQHCe89jy9%PHn zYkBjPSb=|@!#ECgt)I$!+2LVGT4|Iv$w!70%bHE9Bno1yw=c1ceW4&l)N0*3zcP=z zmk5JmZw+r6&fVkQ_oO{aVz?eG^A?p2b@lvT!iJEefZ3+}tGu$KY|IC;co)<=k9H0! zHTqbX_mUx_8*N!7=_RltCd&oP%EPtb08)&QU$jT)f+t*saq1tgz>abYTl0{zpU!7> zfBwG)x_m)#ip2AF&>kc1Yf6TxxKw9>?xb#QE*HtMxfs}nG(iNv3c{P}W%uGN`kUas zY>8?XJAb{NQYn+Xh0CL_D1DE54&0tc-}kO6jj*n-{(?pYELSDLUbQu<8xWVm`R0c%N8;RKaY1g-RGVVs}`|64Omw!7N zOU3P};oY&m??J2LuYAOD@>LPukI1awU~Xv{FRMi(=c_@KCDl z0CrBjJ`36Rsgn7wYliREl@InI0@mo<$!4GDC$CMFrWA5wl^mg)5P%x&C_6bSAFy>Z zf|ZM#-7`o5I;#T6A{gJcqFzuNE zA=FJ{HRA8bvou=M1-in&6B~Q6=Pb$ zfX#E(=vyiB4QRlcnRk0xt9Cho6crI+LN9F&5#}C2E9rnhr>VA!Sy>a~`d%lCD0I3E z&$S$aGCq86IK(o%K(&iqTM6=}P|(c?<3o~sPme}ZRyZF<=WkOXF}>}GR?)-NtUE?G zEmTb2UU6IsT*cMp(RU{qV)NlLSoqvU>ur2J%*j7-UZM?}Jm5Zjb8xfL zrO4)ee4i=#X5JO_MSYyyRwm1WW!(ONWtt!UaC`pht`JGeb-(_OtBT9>`A;9>`L+$l zV9htzbam@Cff!r~@r|@EB+7B_Ipf{g)4?a2+tu0ENV7>#9Fi32B)(gBB|o?Vf@GV| zDWJkJ)Wjc--*=~#n|uRJBhK~m@V|5Gc>x}yW$@x;m2DkWd*8Y6=`F+e@V3o1p$^O0 zZrOXdK{#OWgFrzmL!xGOk2BM;m>oX3lygOY+MHKfLIEt6!;eY%%VM6Q_DVk5MP>#p|n#Oc&XcVpBAG+7;EfD>{&p z3_sn!M;}yrLhlln{ryYbXPW~%CODF!N~wSEYC6Eoj(wZYKIbgk{yC42{R7#Dm6E6Ny~&s=<{TQu#%(25Yxpsfeo%_DufO zrGOdii?&+^W>~vr*b-g6Fr1mkO{I~GxHS?tIq2S_Uem`7i{`p1Ht;V-`QM=*5&DyT zqkJf|1T$~s^RdmKt;e-pYYCpyXi3fgF4PwG=g$=Qb%LHuY(W&g46{;S8!NI-ks$wt zKaUv*r$I_!eB_A-EVeg215b0alXW~X<-RWmuo)tHYdI+|mM%BSPpt4^8ruajCt$Hm zIY;M^jz-F3&4N+XedRY&g36j%zhK9%LW?Sfpd*#qimuFynC1Z9=aw<=pZDitj=7OF z>mA=}c8`5}1e{a-1`1>YJDYjb7|360U4hra_yIt^!mzxoXG3G9fDDxlEcrf#Ddq0L4333*%z#C+9>NiF2h~*O;{E0P>=MB zVyWQ-VXH5QXCM*hMffbo?e61hnzi^ci|S|B+EZg|P4#bg(#O=vTZg4u0;)I4;@0dH z-jhVw+w=C!u0cWY(CP7sB-`9S3TOe|R9YPxYD#%`o|(>dH7swhY{!DRnZyCd#cDo= zm-(pS9~dQC)&S1)DeB^xJ>Kt{xCh~*wz*d}`gd+hAC3+?Xzp|Co+C;OqW5!Vw@op|TA4no16(+a$UIf){_zAI@MSlzVRHQ7qXr$o!= zUa!ZDyjv&IJ#T2GTuvl47M9KT34xl6M)D2^Q4^+L$c>plML0egw9@gq6aT8V`NNhW z^t@g60&jHW_2fx=VmWg%_R~Ug7kf06p1FTYhmzy&?@L-3r?li+O@#Qb(W_b<*3uWf z?cFaHU-@Qmd}|^5M)w{Quu#q$t&_^~$vsGn)r?C2cJA4Zwf9nJwjKD*Q#EiJQ${Kp zcL1hab$molhmEfPVl8`dL7=tO`)M{mH8*_GJ+3-VW-Tk}9agzvLaphE&95novS(FA z$Z7cPyWCTH$CF$}Bc{UjV;=XehjjB@XU0X<8Ylf2?N09YOH#kmnVVbYVa|WS6-0~% z1Nk9Xk%FO*aRqvh6kYZB88zK{@yL^lmpvsn7TxC{QykrwL7z*Py4aSJMZC>q8RG5z8wLi?r=gC` zE8YiwqufD74J%Izt<=C2@G5#TYGsgMZnuV5aU&TIu?8jZ#(+D?V={QUj|=}vY1m+U zMB{N%x`gx{i<}L8v^CpG>+&9yNKz4yo^e~cqrc*LzU^`KFOobR?(?DP=E_ECNjav3 zWFoN7r4g=CJn<(A+9XXGYNHvF@R84^gE(<(-As-yG4VZt4@-iF&j7+|qlo#~loR2I zwtF*A+R_k}39wMu(4{D>;;?8N@~b%Ne9M-`gtKVT6KBsg2hnW9v?rBMKH%F zcT2QwYb$`QfofpZoU*q|{(fe!=x_$}*n-a|iCKQjY;i~tQ@BPa*z+|s;8GqbZGP|G z0otZBd5@OI=}E;f@1sfRb*>S5!4JZsnv(h8-Oy-coh);$;aZYP-w0{B5#2*t5C=f* zCsCXwuBU&8oS#ROPgj;(QKmuJ%?uOfnSSsqUXV48HXB~3uU9Vs?6^84(!ZDYAi4jd zAXK$UCYtfq%eE%_6Mt9Qix~5g--!4KR0J<)JVkKPjgKE?SCI0ckg5&fTTW*sJK{Dc zirH98{7+WR>zT{UmaoXkdW6^cU~#$NDAXKkeDS$zggP z5B{S%Cm>V}%Y7;@ymcbVo1;>7e(a=_Y0T$r>$VdDfrN_z1lkDnimpNSEz`=Mi!+=? z%L-iU5Vjz}V4^;6x|O2W%YEPuz4gv8BnT;-kjOYOzQS=5D`d!|~VI5x8y`_UFuNS5q1iEamI zyB|)1cfunNYBM2VyJ$dAU6tP6XM)zzP*8(uuj4aS0iVy9!HD%*y7)kq%BahR{Z8sr z;oZGoR?~T<9eWOb@4NP%bB=*Vv}pdm22A&iqfRo4oTU>cAETJcIS&e=%zZ=WPgyLMi1P=f9jtB6^-!zy#j&F$llH_)Jca>op+9#GSNfd!1VE! zGR7k2AgkrfBx6)3Wz8mKt4=sLV2h@J6D2`HwSD=aRGfCTkF=l6xaS!Zr7G~2V5ZYQ zA0}*mf%VA)%*JOxVFARh+g5frS(y*U!8D6tTgNbo zK1EC6tMO{c;t>5wY``m$A(Ef_2!4?nEm%@9P5DS-z%WDk&7;6<_{ z#CsgpUv`Tx0yTHThLos_nVp5|o)K5c2(iR6#4PFkK*H4trlTWi4beyy(1({ZW$LAo?%8 z>Sc%#3Ru#%Rq#sM(Lb)B@V@m9-md@m<)T$!2mAFcn`yTyz})!2KH9;aw=eU&JcK6F z;>55q_lKJX6DNY>!xm9s>RKITGMDqXg5?m=0JHzQ3?1|`1ki-8ZO1?W+ZOV!fDZs? zlvN=5BVf1zI=z2>QvrIHVPqRRl_L@Z-oSq5_=PWcPP0RL+QDa3G+AaaO@ z>8sd%R7e>VAE;z5^B;E^Z{RnwNfkam+FVboh%`#8nbqTigBC@&p6qgj@$v{9pdO{Y zYR3uY>BoD3VONSpIL7s4k7;oJQ8R{36uJnB-XW{n9i0>V5;g-D&BAJ-<|}HfjjK#N zP7XK}G&pI6I?3Z4W2PVSI;pJ0NXVB+x*kTe>hb>J))Fj7k19a=L{fW|4=u#>XrY;7 zBS4EYMU?EvPW=~&6+y@=h9g{EQl140d1Kw032+on1ab`UnW6w?2eNyhj)QE27ZwjF lvTJU~cH_ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index ff5abd05..f1be718a 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -1,21 +1,5 @@ - - 看漫画 - IKanman - 动漫之家 - Dmzj - 汗汗漫画 - HHAAZZ - CC图库 - CCTuku - 有妖气 - U17 - - - 看漫画 - IKanman - 动漫之家 - Dmzj - 汗汗漫画 - HHAAZZ - CC图库 - CCTuku - 有妖气 - U17 - E绅士 - EHentai - Ex绅士 - ExHentai - 0 1 diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml new file mode 100644 index 00000000..a623b345 --- /dev/null +++ b/app/src/main/res/values/attrs.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 45b6b2cf..d9103e36 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -3,17 +3,17 @@ #2196F3 #1976D2 #FFC107 + #AAFFC107 + #8A000000 + #FFFAFAFA + #AAFAFAFA + #B3FFFFFF + #FF303030 + #AA303030 - #000000 - #FFFFFF - #E8E8E7 - #7F7F80 - #BEBEBE - - #AAFFC107 + #FF000000 + #FFFFFFFF + #90000000 #4F000000 #AA7F7F80 - #AABEBEBE - #AA000000 - #00FFFFFF diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 348dfe63..05182d14 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,11 +1,11 @@ - Cimoc Cimoc 我的漫画 历史浏览 系统选项 + 图源管理 设置 关于 @@ -29,6 +29,7 @@ 是否删除该历史纪录 是否清除所有历史纪录 + 删除成功 数量为 前面没有了 后面没有了 @@ -44,27 +45,26 @@ 备份成功 数量为 备份失败 没有找到备份文件 - 正在备份.. 恢复 从本地文件中恢复 恢复成功 数量为 - 正在恢复.. 阅读设置 阅读模式 音量键翻页 仅限翻页模式 + 自动切割分页 + 仅限卷纸模式 其他设置 夜间模式 全局夜间模式 首页设置 清除缓存 - 正在清除.. 清除成功 首页选择 阅读模式选择 文件选择 - version: 1.1.0 + version: 1.1.1 源代码 https://github.com/Arachnid-27/Cimoc 支持作者 @@ -73,13 +73,17 @@ cimoc_app@163.com 该邮箱也用于意见反馈 邮箱已复制到剪切板 - 重启软件打开隐藏图源 - 重启软件关闭隐藏图源 操作确认 确定 取消 + 正在执行中.. + 是否删除该图源\n相关的漫画也会被删除 + 添加图源 + 图源已存在 + 添加成功 + 图源错误 看漫画 动漫之家 汗汗漫画 @@ -89,5 +93,5 @@ ExHentai 网络错误 - + null diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index eb97dfb4..16f2d7f6 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,24 +1,53 @@ + - - - - + + + + + + + + + + - + diff --git a/build.gradle b/build.gradle index e73a691f..764194e9 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ buildscript { // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' - classpath 'org.greenrobot:greendao-gradle-plugin:3.0.0' + classpath 'org.greenrobot:greendao-gradle-plugin:3.1.0' } } From b41717a6ee3cd72d95343e3f411d903e56e422ec Mon Sep 17 00:00:00 2001 From: hiroshi Date: Sun, 14 Aug 2016 01:44:15 +0800 Subject: [PATCH 008/521] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BB=8E=E5=8F=B3?= =?UTF-8?q?=E5=BE=80=E5=B7=A6=E7=BF=BB=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 2 +- .../hiroshi/cimoc/core/PreferenceMaster.java | 7 +- .../com/hiroshi/cimoc/model/EventMessage.java | 9 ++ .../cimoc/presenter/DetailPresenter.java | 11 +- .../cimoc/presenter/ReaderPresenter.java | 18 ++- .../cimoc/presenter/SettingsPresenter.java | 19 +-- .../cimoc/ui/activity/BaseActivity.java | 6 +- .../cimoc/ui/activity/DetailActivity.java | 3 +- .../cimoc/ui/activity/MainActivity.java | 3 +- .../cimoc/ui/activity/PageReaderActivity.java | 90 ++++++++++---- .../cimoc/ui/activity/ReaderActivity.java | 70 ++++++++--- .../cimoc/ui/activity/ResultActivity.java | 4 +- .../ui/activity/StreamReaderActivity.java | 113 ++++++++---------- .../cimoc/ui/adapter/PicturePageAdapter.java | 13 +- .../ui/adapter/PictureStreamAdapter.java | 2 +- .../cimoc/ui/adapter/PreloadAdapter.java | 8 ++ .../cimoc/ui/custom/LimitedViewPager.java | 6 - .../ui/custom/PreCacheLayoutManager.java | 34 ++++++ .../cimoc/ui/custom/ReverseSeekBar.java | 37 ++++++ .../cimoc/ui/fragment/SettingsFragment.java | 45 +++++-- .../cimoc/ui/fragment/SourceFragment.java | 2 +- app/src/main/res/layout/custom_back_btn.xml | 2 +- app/src/main/res/layout/custom_mask.xml | 2 +- app/src/main/res/layout/custom_seek_bar.xml | 4 +- app/src/main/res/layout/fragment_about.xml | 2 + app/src/main/res/layout/fragment_settings.xml | 44 ++++++- app/src/main/res/layout/item_picture.xml | 2 +- app/src/main/res/values/arrays.xml | 9 -- app/src/main/res/values/colors.xml | 1 - app/src/main/res/values/strings.xml | 4 +- 30 files changed, 384 insertions(+), 188 deletions(-) create mode 100644 app/src/main/java/com/hiroshi/cimoc/ui/custom/PreCacheLayoutManager.java create mode 100644 app/src/main/java/com/hiroshi/cimoc/ui/custom/ReverseSeekBar.java diff --git a/app/build.gradle b/app/build.gradle index 1dfe5d5a..e7abc4da 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,7 +11,7 @@ android { minSdkVersion 15 targetSdkVersion 23 versionCode 1 - versionName "1.1.1" + versionName "1.2.0" resConfigs "en", "zh" } buildTypes { diff --git a/app/src/main/java/com/hiroshi/cimoc/core/PreferenceMaster.java b/app/src/main/java/com/hiroshi/cimoc/core/PreferenceMaster.java index 9d3ce8b7..9773f675 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/PreferenceMaster.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/PreferenceMaster.java @@ -11,8 +11,8 @@ public class PreferenceMaster { public static final int MODE_HORIZONTAL_PAGE = 0; - public static final int MODE_HORIZONTAL_STREAM = 1; - public static final int MODE_VERTICAL_STREAM = 2; + public static final int MODE_PORTRAIT_STREAM = 1; + public static final int MODE_LANDSCAPE_STREAM = 2; public static final int HOME_CIMOC = 0; public static final int HOME_FAVORITE = 1; @@ -21,8 +21,9 @@ public class PreferenceMaster { public static final String PREF_HOME = "pref_home"; public static final String PREF_MODE = "pref_mode"; public static final String PREF_VOLUME = "pref_volume"; - public static final String PREF_NIGHTLY = "pref_nightly"; + public static final String PREF_NIGHT = "pref_night"; public static final String PREF_SPLIT = "pref_split"; + public static final String PREF_REVERSE = "pref_reverse"; private static final String PREFERENCES_NAME = "cimoc_preferences"; diff --git a/app/src/main/java/com/hiroshi/cimoc/model/EventMessage.java b/app/src/main/java/com/hiroshi/cimoc/model/EventMessage.java index bf3be38e..43d0b005 100644 --- a/app/src/main/java/com/hiroshi/cimoc/model/EventMessage.java +++ b/app/src/main/java/com/hiroshi/cimoc/model/EventMessage.java @@ -23,12 +23,19 @@ public class EventMessage { private int type; private Object data; + private Object second; public EventMessage(int type, Object data) { this.type = type; this.data = data; } + public EventMessage(int type, Object data, Object second) { + this.type = type; + this.data = data; + this.second = second; + } + public int getType() { return type; } @@ -37,4 +44,6 @@ public Object getData() { return data; } + public Object getSecond() { return second; } + } diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/DetailPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/DetailPresenter.java index e23c9f59..9aa8ca91 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/DetailPresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/DetailPresenter.java @@ -44,9 +44,6 @@ public void onCreate() { public void onDestroy() { super.onDestroy(); mManga.cancel(); - if (mComic.getId() != null) { - mComicManager.updateComic(mComic); - } } public Comic getComic() { @@ -91,18 +88,24 @@ public void onEvent(EventMessage msg) { break; case EventMessage.COMIC_LAST_CHANGE: String last = (String) msg.getData(); + int page = (int) msg.getSecond(); mComic.setHistory(System.currentTimeMillis()); mComic.setLast(last); - mComic.setPage(1); + mComic.setPage(page); if (mComic.getId() == null) { long id = mComicManager.insertComic(mComic); mComic.setId(id); + } else { + mComicManager.updateComic(mComic); } EventBus.getDefault().post(new EventMessage(EventMessage.HISTORY_COMIC, new MiniComic(mComic))); mDetailActivity.setLastChapter(last); break; case EventMessage.COMIC_PAGE_CHANGE: mComic.setPage((Integer) msg.getData()); + if (mComic.getId() != null) { + mComicManager.updateComic(mComic); + } break; } } diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/ReaderPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/ReaderPresenter.java index 628c0518..7bb8f7b2 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/ReaderPresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/ReaderPresenter.java @@ -31,10 +31,10 @@ public class ReaderPresenter extends BasePresenter { private String cid; private String last; - private Integer page; + private int page; private int status; - public ReaderPresenter(ReaderActivity activity, int source, String cid, String last, Integer page, Chapter[] array, int position) { + public ReaderPresenter(ReaderActivity activity, int source, String cid, String last, int page, Chapter[] array, int position) { mReaderActivity = activity; mPreloadAdapter = new PreloadAdapter(array, position); mManga = SourceManager.getManga(source); @@ -109,10 +109,18 @@ public void onChapterToPrev() { switchChapter(chapter.getCount(), chapter.getCount(), chapter.getTitle(), chapter.getPath()); } + public int getChapterPosition() { + return mPreloadAdapter.getCurrent(); + } + + public Chapter getCurrentChapter() { + return mPreloadAdapter.currentChapter(); + } + private void switchChapter(int progress, int count, String title, String path) { mReaderActivity.updateChapterInfo(count, title); mReaderActivity.setReadProgress(progress); - EventBus.getDefault().post(new EventMessage(EventMessage.COMIC_LAST_CHANGE, path)); + EventBus.getDefault().post(new EventMessage(EventMessage.COMIC_LAST_CHANGE, path, progress)); } @Subscribe(threadMode = ThreadMode.MAIN) @@ -124,11 +132,11 @@ public void onEvent(EventMessage msg) { if (!mPreloadAdapter.isLoad()) { mReaderActivity.setNextImage(array); chapter = mPreloadAdapter.moveNext(); - if (!chapter.getPath().equals(last) || page == null) { + if (!chapter.getPath().equals(last) || page == -1) { page = 1; } mReaderActivity.initLoad(page, array.length, chapter.getTitle()); - EventBus.getDefault().post(new EventMessage(EventMessage.COMIC_LAST_CHANGE, chapter.getPath())); + EventBus.getDefault().post(new EventMessage(EventMessage.COMIC_LAST_CHANGE, chapter.getPath(), page)); } else { if (status == LOAD_PREV) { mReaderActivity.setPrevImage(array); diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/SettingsPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/SettingsPresenter.java index e213a655..8e5ea79a 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/SettingsPresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/SettingsPresenter.java @@ -26,23 +26,17 @@ public SettingsPresenter(SettingsFragment fragment) { mComicManager = ComicManager.getInstance(); } - public void onCacheBtnClick() { - mSettingsFragment.showProgressDialog(); + public void clearCache() { FileUtils.deleteDir(mSettingsFragment.getActivity().getCacheDir()); - mSettingsFragment.showSnackbar(R.string.settings_other_cache_success); - mSettingsFragment.hideProgressDialog(); } - public void onBackupBtnClick() { - mSettingsFragment.showProgressDialog(); + public int backup() { List list = mComicManager.listBackup(); if (BackupUtils.saveComic(list)) { - String text = mSettingsFragment.getString(R.string.settings_backup_save_success) + list.size(); - mSettingsFragment.showSnackbar(text); + return list.size(); } else { - mSettingsFragment.showSnackbar(R.string.settings_backup_save_fail); + return -1; } - mSettingsFragment.hideProgressDialog(); } public String[] getFiles() { @@ -53,8 +47,7 @@ public String[] getFiles() { return files; } - public void onRestorePositiveBtnClick(String name) { - mSettingsFragment.showProgressDialog(); + public void restore(String name) { List list = BackupUtils.restoreComic(name); mComicManager.restoreFavorite(list); } @@ -65,9 +58,9 @@ public void onEvent(EventMessage msg) { switch (msg.getType()) { case EventMessage.RESTORE_FAVORITE: List list = (List) msg.getData(); - mSettingsFragment.hideProgressDialog(); String text = mSettingsFragment.getString(R.string.settings_backup_restore_success) + list.size(); mSettingsFragment.showSnackbar(text); + mSettingsFragment.hideProgressDialog(); break; } } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/BaseActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/BaseActivity.java index 6a0f3290..d8f1c50b 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/BaseActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/BaseActivity.java @@ -29,7 +29,7 @@ protected void onCreate(Bundle savedInstanceState) { setContentView(getLayoutRes()); ButterKnife.bind(this); initToolbar(); - initPresenter(); + initPresenter(savedInstanceState); initView(); if (getPresenter() != null) { getPresenter().onCreate(); @@ -49,7 +49,7 @@ protected void initOrientation() { } protected void initTheme() { - boolean nightly = CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_NIGHTLY, false); + boolean nightly = CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_NIGHT, false); if (nightly) { setTheme(R.style.AppThemeDark); } else { @@ -78,7 +78,7 @@ protected BasePresenter getPresenter() { return null; } - protected void initPresenter() {} + protected void initPresenter(Bundle savedInstanceState) {} protected void initView() {} diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/DetailActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/DetailActivity.java index 12d02cd9..f95b6cb3 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/DetailActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/DetailActivity.java @@ -2,6 +2,7 @@ import android.content.Context; import android.content.Intent; +import android.os.Bundle; import android.support.design.widget.CoordinatorLayout; import android.support.design.widget.FloatingActionButton; import android.support.v7.widget.GridLayoutManager; @@ -59,7 +60,7 @@ public void onClick(View v) { } @Override - protected void initPresenter() { + protected void initPresenter(Bundle savedInstanceState) { long id = getIntent().getLongExtra(EXTRA_ID, -1); int source = getIntent().getIntExtra(EXTRA_SOURCE, -1); String cid = getIntent().getStringExtra(EXTRA_CID); diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/MainActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/MainActivity.java index a244cf32..ceeb372d 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/MainActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/MainActivity.java @@ -1,6 +1,7 @@ package com.hiroshi.cimoc.ui.activity; import android.content.Intent; +import android.os.Bundle; import android.support.design.widget.NavigationView; import android.support.v4.view.GravityCompat; import android.support.v4.widget.DrawerLayout; @@ -80,7 +81,7 @@ public boolean onNavigationItemSelected(MenuItem item) { } @Override - protected void initPresenter() { + protected void initPresenter(Bundle savedInstanceState) { int home = CimocApplication.getPreferences().getInt(PreferenceMaster.PREF_HOME, PreferenceMaster.HOME_CIMOC); mPresenter = new MainPresenter(this, PreferenceMaster.getHomeId(home)); } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/PageReaderActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/PageReaderActivity.java index 800e6bb1..adb8dd36 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/PageReaderActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/PageReaderActivity.java @@ -7,11 +7,11 @@ import com.hiroshi.cimoc.CimocApplication; import com.hiroshi.cimoc.R; +import com.hiroshi.cimoc.core.PreferenceMaster; import com.hiroshi.cimoc.ui.adapter.PicturePageAdapter; import com.hiroshi.cimoc.ui.custom.LimitedViewPager; import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeView; import com.hiroshi.cimoc.utils.ControllerBuilderFactory; -import com.hiroshi.cimoc.core.PreferenceMaster; import org.adw.library.widgets.discreteseekbar.DiscreteSeekBar; @@ -29,6 +29,7 @@ public class PageReaderActivity extends ReaderActivity implements OnPageChangeLi private PicturePageAdapter mPageAdapter; private boolean volume; + private boolean isReverse; @Override public boolean onKeyDown(int keyCode, KeyEvent event) { @@ -47,14 +48,18 @@ public boolean onKeyDown(int keyCode, KeyEvent event) { @Override protected void initView() { - super.initView(); - volume = CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_VOLUME, false); - mPageAdapter = new PicturePageAdapter(new LinkedList(), getLayoutInflater(), - ControllerBuilderFactory.getControllerBuilder(source, this), this); - mViewPager.addOnPageChangeListener(this); - mViewPager.setAdapter(mPageAdapter); - mViewPager.setCurrentItem(PicturePageAdapter.MAX_COUNT / 2 + 1, false); - mViewPager.setOffscreenPageLimit(3); + if (shouldCreate()) { + super.initView(); + isReverse = CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_REVERSE, false); + mSeekBar.setReverse(isReverse); + volume = CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_VOLUME, false); + mPageAdapter = new PicturePageAdapter(new LinkedList(), getLayoutInflater(), + ControllerBuilderFactory.getControllerBuilder(source, this), this); + mViewPager.addOnPageChangeListener(this); + mViewPager.setAdapter(mPageAdapter); + mViewPager.setCurrentItem(PicturePageAdapter.MAX_COUNT / 2 + 1, false); + mViewPager.setOffscreenPageLimit(3); + } } @Override @@ -74,12 +79,22 @@ public void onPageSelected(int position) { } else { mViewPager.setLimit(LimitedViewPager.LIMIT_NONE); } - if (position > current && progress == max) { - mPresenter.onChapterToNext(); - } else if (position < current && progress == 1) { - mPresenter.onChapterToPrev(); + if (isReverse) { + if (position < current && progress == max) { + mPresenter.onChapterToNext(); + } else if (position > current && progress == 1) { + mPresenter.onChapterToPrev(); + } else { + setReadProgress(progress + current - position); + } } else { - setReadProgress(progress + position - current); + if (position > current && progress == max) { + mPresenter.onChapterToNext(); + } else if (position < current && progress == 1) { + mPresenter.onChapterToPrev(); + } else { + setReadProgress(progress + position - current); + } } } @@ -90,7 +105,7 @@ public void onPageScrollStateChanged(int state) { hideToolLayout(); break; case ViewPager.SCROLL_STATE_IDLE: - if (mViewPager.getLimit() == LimitedViewPager.LIMIT_LEFT) { + if (isReverse && mPageAdapter.isToLeft() || !isReverse && mPageAdapter.isToRight()) { mPresenter.loadNext(); } break; @@ -100,7 +115,8 @@ public void onPageScrollStateChanged(int state) { @Override public void onProgressChanged(DiscreteSeekBar seekBar, int value, boolean fromUser) { if (fromUser) { - mViewPager.setCurrentItem(mPageAdapter.getCurrent() + value - progress); + int offset = isReverse ? progress - value : value - progress; + mViewPager.setCurrentItem(mPageAdapter.getCurrent() + offset); } } @@ -111,14 +127,16 @@ public void onSingleTap(PhotoDraweeView draweeView, float x, float y) { float limitX = point.x / 3.0f; float limitY = point.y / 3.0f; if (x < limitX) { + hideToolLayout(); mViewPager.prevPage(); } else if (x > 2 * limitX) { + hideToolLayout(); mViewPager.nextPage(); } else if (y >= 2 * limitY) { switchToolLayout(); } else if (y >= limitY) { draweeView.retry(); - } else if (mPageAdapter.isToLeft()) { + } else if (!isReverse && mPageAdapter.isToLeft() || isReverse && mPageAdapter.isToRight()) { mPresenter.loadPrev(); } } @@ -130,18 +148,38 @@ protected int getLayoutRes() { @Override public void setPrevImage(String[] array) { - mPageAdapter.setPrevImages(array); + if (isReverse) { + int size = array.length; + for (int i = 0; i != size / 2; ++i) { + String temp = array[i]; + array[i] = array[size - i - 1]; + array[size - i - 1] = temp; + } + mPageAdapter.setNextImages(array); + } else { + mPageAdapter.setPrevImages(array); + } } @Override public void setNextImage(String[] array) { - mPageAdapter.setNextImages(array); + if (isReverse) { + int size = array.length; + for (int i = 0; i != size / 2; ++i) { + String temp = array[i]; + array[i] = array[size - i - 1]; + array[size - i - 1] = temp; + } + mPageAdapter.setPrevImages(array); + } else { + mPageAdapter.setNextImages(array); + } } @Override public void loadSuccess(boolean isNext) { - if (isNext && mViewPager.getLimit() == LimitedViewPager.LIMIT_LEFT || - !isNext && mViewPager.getLimit() == LimitedViewPager.LIMIT_RIGHT) { + if (!isReverse && (isNext && mPageAdapter.isToRight() || !isNext && mPageAdapter.isToLeft()) + || isReverse && (isNext && mPageAdapter.isToLeft() || !isNext && mPageAdapter.isToRight())) { mViewPager.setLimit(LimitedViewPager.LIMIT_NONE); } showToast(R.string.reader_load_success); @@ -151,11 +189,19 @@ public void loadSuccess(boolean isNext) { public void initLoad(int progress, int max, String title) { super.initLoad(progress, max, title); if (progress != 1) { - mViewPager.setCurrentItem(PicturePageAdapter.MAX_COUNT / 2 + progress); + if (isReverse) { + mViewPager.setCurrentItem(PicturePageAdapter.MAX_COUNT / 2 + progress); + } else { + mViewPager.setCurrentItem(PicturePageAdapter.MAX_COUNT / 2 - progress + 1); + } } else { if (mPageAdapter.isToBoth()) { mViewPager.setLimit(LimitedViewPager.LIMIT_BOTH); mPresenter.loadNext(); + } else if (isReverse) { + mViewPager.setLimit(LimitedViewPager.LIMIT_LEFT); + mPageAdapter.setCurrent(PicturePageAdapter.MAX_COUNT / 2); + mViewPager.setCurrentItem(PicturePageAdapter.MAX_COUNT / 2, false); } else { mViewPager.setLimit(LimitedViewPager.LIMIT_RIGHT); } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java index 0149b499..b6108ffa 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java @@ -2,18 +2,22 @@ import android.content.Context; import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.res.Configuration; +import android.os.Bundle; import android.view.View; import android.widget.TextView; import android.widget.Toast; import com.hiroshi.cimoc.CimocApplication; import com.hiroshi.cimoc.R; +import com.hiroshi.cimoc.core.PreferenceMaster; import com.hiroshi.cimoc.model.Chapter; import com.hiroshi.cimoc.model.Comic; import com.hiroshi.cimoc.presenter.BasePresenter; import com.hiroshi.cimoc.presenter.ReaderPresenter; +import com.hiroshi.cimoc.ui.custom.ReverseSeekBar; import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeViewController.OnSingleTapListener; -import com.hiroshi.cimoc.core.PreferenceMaster; import org.adw.library.widgets.discreteseekbar.DiscreteSeekBar; import org.adw.library.widgets.discreteseekbar.DiscreteSeekBar.OnProgressChangeListener; @@ -33,7 +37,7 @@ public abstract class ReaderActivity extends BaseActivity implements OnSingleTap @BindView(R.id.reader_progress_layout) View mProgressLayout; @BindView(R.id.reader_back_layout) View mBackLayout; @BindView(R.id.reader_loading_layout) View mLoadingLayout; - @BindView(R.id.reader_seek_bar) DiscreteSeekBar mSeekBar; + @BindView(R.id.reader_seek_bar) ReverseSeekBar mSeekBar; @BindView(R.id.reader_mask) View mNightMask; protected ReaderPresenter mPresenter; @@ -41,31 +45,55 @@ public abstract class ReaderActivity extends BaseActivity implements OnSingleTap protected int progress; protected int max; + private boolean isLandscape; + @Override protected void initView() { - if (CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_NIGHTLY, false)) { + if (CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_NIGHT, false)) { mNightMask.setVisibility(View.VISIBLE); } progress = max = 1; mSeekBar.setOnProgressChangeListener(this); + } @Override protected void onPause() { super.onPause(); - mPresenter.setPage(progress); + if (mPresenter != null) { + mPresenter.setPage(progress); + } + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + if (mPresenter != null) { + getIntent().putExtra(EXTRA_PAGE, progress); + getIntent().putExtra(EXTRA_POSITION, mPresenter.getChapterPosition()); + getIntent().putExtra(EXTRA_LAST, mPresenter.getCurrentChapter().getPath()); + } } @OnClick(R.id.reader_back_btn) void onBackClick() { onBackPressed(); } + @Override + protected void initTheme() { + setTheme(R.style.ReaderTheme); + } + @Override protected void initToolbar() {} @Override - protected void initTheme() { - setTheme(R.style.ReaderTheme); + protected void initOrientation() { + int mode = CimocApplication.getPreferences().getInt(PreferenceMaster.PREF_MODE, PreferenceMaster.MODE_HORIZONTAL_PAGE); + isLandscape = mode == PreferenceMaster.MODE_LANDSCAPE_STREAM; + if (isLandscape) { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); + } } @Override @@ -74,16 +102,26 @@ protected BasePresenter getPresenter() { } @Override - protected void initPresenter() { - source = getIntent().getIntExtra(EXTRA_SOURCE, -1); - String cid = getIntent().getStringExtra(EXTRA_CID); - String last = getIntent().getStringExtra(EXTRA_LAST); - int page = getIntent().getIntExtra(EXTRA_PAGE, -1); - String[] title = getIntent().getStringArrayExtra(EXTRA_TITLE); - String[] path = getIntent().getStringArrayExtra(EXTRA_PATH); - Chapter[] array = fromArray(title, path); - int position = getIntent().getIntExtra(EXTRA_POSITION, 0); - mPresenter = new ReaderPresenter(this, source, cid, last, page, array, position); + protected void initPresenter(Bundle savedInstanceState) { + if (shouldCreate()) { + source = getIntent().getIntExtra(EXTRA_SOURCE, -1); + String cid = getIntent().getStringExtra(EXTRA_CID); + String last = getIntent().getStringExtra(EXTRA_LAST); + int page = getIntent().getIntExtra(EXTRA_PAGE, -1); + String[] title = getIntent().getStringArrayExtra(EXTRA_TITLE); + String[] path = getIntent().getStringArrayExtra(EXTRA_PATH); + Chapter[] array = fromArray(title, path); + int position = getIntent().getIntExtra(EXTRA_POSITION, 0); + mPresenter = new ReaderPresenter(this, source, cid, last, page, array, position); + } + } + + protected boolean shouldCreate() { + if (isLandscape) { + return getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; + } else { + return getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT; + } } @Override diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/ResultActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/ResultActivity.java index 89f3cff0..1d6d22ee 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/ResultActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/ResultActivity.java @@ -2,6 +2,7 @@ import android.content.Context; import android.content.Intent; +import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; @@ -10,7 +11,6 @@ import com.hiroshi.cimoc.R; import com.hiroshi.cimoc.model.Comic; -import com.hiroshi.cimoc.model.Source; import com.hiroshi.cimoc.presenter.BasePresenter; import com.hiroshi.cimoc.presenter.ResultPresenter; import com.hiroshi.cimoc.ui.adapter.BaseAdapter; @@ -35,7 +35,7 @@ public class ResultActivity extends BaseActivity { private ResultPresenter mPresenter; @Override - protected void initPresenter() { + protected void initPresenter(Bundle savedInstanceState) { String keyword = getIntent().getStringExtra(EXTRA_KEYWORD); int source = getIntent().getIntExtra(EXTRA_SOURCE, -1); mPresenter = new ResultPresenter(this, source, keyword); diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/StreamReaderActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/StreamReaderActivity.java index 6d6fec4f..31ac44ec 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/StreamReaderActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/StreamReaderActivity.java @@ -1,16 +1,15 @@ package com.hiroshi.cimoc.ui.activity; -import android.content.pm.ActivityInfo; import android.graphics.Point; -import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import com.hiroshi.cimoc.CimocApplication; import com.hiroshi.cimoc.R; +import com.hiroshi.cimoc.core.PreferenceMaster; import com.hiroshi.cimoc.ui.adapter.PictureStreamAdapter; +import com.hiroshi.cimoc.ui.custom.PreCacheLayoutManager; import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeView; import com.hiroshi.cimoc.utils.ControllerBuilderFactory; -import com.hiroshi.cimoc.core.PreferenceMaster; import org.adw.library.widgets.discreteseekbar.DiscreteSeekBar; @@ -26,67 +25,63 @@ public class StreamReaderActivity extends ReaderActivity { @BindView(R.id.reader_recycler_view) RecyclerView mRecyclerView; private PictureStreamAdapter mStreamAdapter; - private LinearLayoutManager mLayoutManager; + private PreCacheLayoutManager mLayoutManager; - private int position; - - @Override - protected void onPause() { - super.onPause(); - mPresenter.setPage(progress); - } + private int position = 0; @Override protected void initView() { - super.initView(); - boolean split = CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_SPLIT, false); - position = 0; - mLayoutManager = new LinearLayoutManager(this); - mStreamAdapter = new PictureStreamAdapter(this, ControllerBuilderFactory.getControllerBuilder(source, this), this, split); - mRecyclerView.setItemAnimator(null); - mRecyclerView.setLayoutManager(mLayoutManager); - mRecyclerView.setAdapter(mStreamAdapter); - mRecyclerView.addItemDecoration(mStreamAdapter.getItemDecoration()); - mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { - @Override - public void onScrollStateChanged(RecyclerView recyclerView, int newState) { - switch (newState) { - case RecyclerView.SCROLL_STATE_DRAGGING: - hideToolLayout(); - break; - case RecyclerView.SCROLL_STATE_IDLE: - case RecyclerView.SCROLL_STATE_SETTLING: - int item = mLayoutManager.findLastVisibleItemPosition(); - if (item == mStreamAdapter.getItemCount() - 1) { - mPresenter.loadNext(); - } - break; + if (shouldCreate()) { + super.initView(); + boolean split = CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_SPLIT, false); + mLayoutManager = new PreCacheLayoutManager(this); + mLayoutManager.setExtraSpace(8); + mStreamAdapter = new PictureStreamAdapter(this, ControllerBuilderFactory.getControllerBuilder(source, this), this, split); + mRecyclerView.setItemAnimator(null); + mRecyclerView.setLayoutManager(mLayoutManager); + mRecyclerView.setAdapter(mStreamAdapter); + mRecyclerView.addItemDecoration(mStreamAdapter.getItemDecoration()); + mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrollStateChanged(RecyclerView recyclerView, int newState) { + switch (newState) { + case RecyclerView.SCROLL_STATE_DRAGGING: + hideToolLayout(); + break; + case RecyclerView.SCROLL_STATE_IDLE: + case RecyclerView.SCROLL_STATE_SETTLING: + int item = mLayoutManager.findLastVisibleItemPosition(); + if (item == mStreamAdapter.getItemCount() - 1) { + mPresenter.loadNext(); + } + break; + } } - } - - @Override - public void onScrolled(RecyclerView recyclerView, int dx, int dy) { - int item = mLayoutManager.findFirstVisibleItemPosition(); - if (item != position) { - position = item; - if (dy > 0) { - if (progress == max) { - mPresenter.onChapterToNext(); - } else { - setReadProgress(progress + 1); - } - } else if (dy < 0) { - if (progress == 1) { - mPresenter.onChapterToPrev(); + + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + int item = mLayoutManager.findFirstVisibleItemPosition(); + if (item != position) { + position = item; + if (dy > 0) { + if (progress == max) { + mPresenter.onChapterToNext(); + } else { + setReadProgress(progress + 1); + } + } else if (dy < 0) { + if (progress == 1) { + mPresenter.onChapterToPrev(); + } else { + setReadProgress(progress - 1); + } } else { - setReadProgress(progress - 1); + setReadProgress(progress); } - } else { - setReadProgress(progress); } } - } - }); + }); + } } @Override @@ -115,14 +110,6 @@ protected int getLayoutRes() { return R.layout.activity_stream_reader; } - @Override - protected void initOrientation() { - int mode = CimocApplication.getPreferences().getInt(PreferenceMaster.PREF_MODE, PreferenceMaster.MODE_VERTICAL_STREAM); - if (mode == PreferenceMaster.MODE_VERTICAL_STREAM) { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); - } - } - @Override public void setPrevImage(String[] array) { mStreamAdapter.addAll(0, Arrays.asList(array)); diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePageAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePageAdapter.java index 2742accc..525b1b38 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePageAdapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePageAdapter.java @@ -28,7 +28,6 @@ public class PicturePageAdapter extends PagerAdapter { private LayoutInflater inflater; private OnSingleTapListener listener; private PipelineDraweeControllerBuilder builder; - private PhotoDraweeView item; private int left; private int right; @@ -45,16 +44,6 @@ public PicturePageAdapter(List images, LayoutInflater inflater, Pipeline this.right = MAX_COUNT / 2 + 1; } - @Override - public void setPrimaryItem(ViewGroup container, int position, Object object) { - super.setPrimaryItem(container, position, object); - item = (PhotoDraweeView) ((View) object).findViewById(R.id.picture_image_view); - } - - public PhotoDraweeView getPrimaryItem() { - return item; - } - public void setCurrent(int current) { this.current = current; } @@ -112,7 +101,7 @@ public void destroyItem(ViewGroup container, int position, Object object) { public Object instantiateItem(ViewGroup container, int position) { View child = inflater.inflate(R.layout.item_picture, container, false); if (left < position && position < right) { - final PhotoDraweeView draweeView = (PhotoDraweeView) child.findViewById(R.id.picture_image_view); + final PhotoDraweeView draweeView = (PhotoDraweeView) child.findViewById(R.id.reader_image_view); draweeView.setScaleType(ImageView.ScaleType.FIT_CENTER); draweeView.setHorizontalMode(); draweeView.setOnSingleTapListener(listener); diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PictureStreamAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PictureStreamAdapter.java index add67868..354b16f6 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PictureStreamAdapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PictureStreamAdapter.java @@ -43,7 +43,7 @@ public PictureStreamAdapter(Context context, PipelineDraweeControllerBuilder bui } public class ViewHolder extends BaseViewHolder { - @BindView(R.id.picture_image_view) PhotoDraweeView photoView; + @BindView(R.id.reader_image_view) PhotoDraweeView photoView; public ViewHolder(View view) { super(view); diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PreloadAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PreloadAdapter.java index 4eaf699c..4fce0239 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PreloadAdapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PreloadAdapter.java @@ -41,6 +41,14 @@ public Chapter nextChapter() { return null; } + public Chapter currentChapter() { + return array[index]; + } + + public int getCurrent() { + return index; + } + public Chapter movePrev() { return array[prev++]; } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/custom/LimitedViewPager.java b/app/src/main/java/com/hiroshi/cimoc/ui/custom/LimitedViewPager.java index c3268832..e0aeacc9 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/custom/LimitedViewPager.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/custom/LimitedViewPager.java @@ -19,16 +19,10 @@ public class LimitedViewPager extends ViewPager { public LimitedViewPager(Context context, AttributeSet attrs) { super(context, attrs); - init(); } public LimitedViewPager(Context context) { super(context); - init(); - } - - private void init() { - limit = LIMIT_BOTH; } private float lastX; diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/custom/PreCacheLayoutManager.java b/app/src/main/java/com/hiroshi/cimoc/ui/custom/PreCacheLayoutManager.java new file mode 100644 index 00000000..748684b9 --- /dev/null +++ b/app/src/main/java/com/hiroshi/cimoc/ui/custom/PreCacheLayoutManager.java @@ -0,0 +1,34 @@ +package com.hiroshi.cimoc.ui.custom; + +import android.content.Context; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; + +/** + * Created by Hiroshi on 2016/8/13. + */ +public class PreCacheLayoutManager extends LinearLayoutManager { + + private int mExtraSpace = 0; + + public PreCacheLayoutManager(Context context) { + super(context); + } + + public PreCacheLayoutManager(Context context, int orientation, boolean reverseLayout) { + super(context, orientation, reverseLayout); + } + + public void setExtraSpace(int extraSpace) { + mExtraSpace = extraSpace; + } + + @Override + protected int getExtraLayoutSpace(RecyclerView.State state) { + if (mExtraSpace > 0) { + return mExtraSpace * getHeight(); + } + return 0; + } + +} diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/custom/ReverseSeekBar.java b/app/src/main/java/com/hiroshi/cimoc/ui/custom/ReverseSeekBar.java new file mode 100644 index 00000000..384aac9b --- /dev/null +++ b/app/src/main/java/com/hiroshi/cimoc/ui/custom/ReverseSeekBar.java @@ -0,0 +1,37 @@ +package com.hiroshi.cimoc.ui.custom; + +import android.content.Context; +import android.util.AttributeSet; + +import org.adw.library.widgets.discreteseekbar.DiscreteSeekBar; + +/** + * Created by Hiroshi on 2016/8/13. + */ +public class ReverseSeekBar extends DiscreteSeekBar { + + private boolean isReverse = false; + + public ReverseSeekBar(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + public ReverseSeekBar(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public ReverseSeekBar(Context context) { + super(context); + } + + @Override + public boolean isRtl() { + return isReverse; + } + + public void setReverse(boolean reverse) { + isReverse = reverse; + invalidate(); + } + +} diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SettingsFragment.java b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SettingsFragment.java index e3c401dc..fa7ac218 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SettingsFragment.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SettingsFragment.java @@ -25,7 +25,8 @@ public class SettingsFragment extends BaseFragment { @BindView(R.id.settings_reader_mode_summary) TextView mModeSummary; @BindView(R.id.settings_reader_split_checkbox) CheckBox mSplitBox; @BindView(R.id.settings_reader_volume_checkbox) CheckBox mVolumeBox; - @BindView(R.id.settings_other_nightly_checkbox) CheckBox mNightlyBox; + @BindView(R.id.settings_reader_reverse_checkbox) CheckBox mReverseBox; + @BindView(R.id.settings_other_night_checkbox) CheckBox mNightBox; private SettingsPresenter mPresenter; private PreferenceMaster mPreference; @@ -36,7 +37,8 @@ public class SettingsFragment extends BaseFragment { private int mTempChoice; private boolean mSplitChoice; private boolean mVolumeChoice; - private boolean mNightlyChoice; + private boolean mNightChoice; + private boolean mReverseChoice; private OnClickListener mSingleChoiceListener = new OnClickListener() { @Override @@ -52,17 +54,19 @@ protected void initView() { mModeChoice = mPreference.getInt(PreferenceMaster.PREF_MODE, PreferenceMaster.MODE_HORIZONTAL_PAGE); mSplitChoice = mPreference.getBoolean(PreferenceMaster.PREF_SPLIT, false); mVolumeChoice = mPreference.getBoolean(PreferenceMaster.PREF_VOLUME, false); - mNightlyChoice = mPreference.getBoolean(PreferenceMaster.PREF_NIGHTLY, false); + mNightChoice = mPreference.getBoolean(PreferenceMaster.PREF_NIGHT, false); + mReverseChoice = mPreference.getBoolean(PreferenceMaster.PREF_REVERSE, false); mHomeSummary.setText(getResources().getStringArray(R.array.home_items)[mHomeChoice]); mModeSummary.setText(getResources().getStringArray(R.array.mode_items)[mModeChoice]); mVolumeBox.setChecked(mVolumeChoice); - mNightlyBox.setChecked(mNightlyChoice); + mNightBox.setChecked(mNightChoice); + mReverseBox.setChecked(mReverseChoice); } - @OnClick(R.id.settings_other_nightly_btn) void onNightlyBtnClick() { - mNightlyChoice = !mNightlyChoice; - mNightlyBox.setChecked(mNightlyChoice); - mPreference.putBoolean(PreferenceMaster.PREF_NIGHTLY, mNightlyChoice); + @OnClick(R.id.settings_other_night_btn) void onNightBtnClick() { + mNightChoice = !mNightChoice; + mNightBox.setChecked(mNightChoice); + mPreference.putBoolean(PreferenceMaster.PREF_NIGHT, mNightChoice); ((MainActivity) getActivity()).restart(); } @@ -78,6 +82,12 @@ protected void initView() { mPreference.putBoolean(PreferenceMaster.PREF_VOLUME, mVolumeChoice); } + @OnClick(R.id.settings_reader_reverse_btn) void onReverseClick() { + mReverseChoice = !mReverseChoice; + mReverseBox.setChecked(mReverseChoice); + mPreference.putBoolean(PreferenceMaster.PREF_REVERSE, mReverseChoice); + } + @OnClick(R.id.settings_backup_restore_btn) void onRestoreBtnClick() { final String[] array = mPresenter.getFiles(); if (array == null) { @@ -89,13 +99,13 @@ protected void initView() { @Override public void onClick(DialogInterface dialog, int which) { mBackupChoice = mTempChoice; - mPresenter.onRestorePositiveBtnClick(array[mBackupChoice]); + showProgressDialog(); + mPresenter.restore(array[mBackupChoice]); } }).show(); } @OnClick(R.id.settings_other_home_btn) void onHomeBtnClick() { - final int[] array = new int[] { R.id.drawer_cimoc, R.id.drawer_favorite, R.id.drawer_history }; DialogFactory.buildSingleChoiceDialog(getActivity(), R.string.settings_select_home, R.array.home_items, mHomeChoice, mSingleChoiceListener, new OnClickListener() { @Override @@ -120,11 +130,22 @@ public void onClick(DialogInterface dialog, int which) { } @OnClick(R.id.settings_backup_save_btn) void onSaveBtnClick() { - mPresenter.onBackupBtnClick(); + showProgressDialog(); + int size = mPresenter.backup(); + if (size != -1) { + String text = getString(R.string.settings_backup_save_success) + size; + showSnackbar(text); + } else { + showSnackbar(R.string.settings_backup_save_fail); + } + hideProgressDialog(); } @OnClick(R.id.settings_other_cache_btn) void onCacheBtnClick() { - mPresenter.onCacheBtnClick(); + showProgressDialog(); + mPresenter.clearCache(); + showSnackbar(R.string.settings_other_cache_success); + hideProgressDialog(); } @Override diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SourceFragment.java b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SourceFragment.java index 457722c8..6fc647d6 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SourceFragment.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SourceFragment.java @@ -65,7 +65,7 @@ public void onItemCheckedListener(boolean isChecked, int position) { final EditText editText = (EditText) view.findViewById(R.id.source_edit_text); builder.setTitle(R.string.source_add); builder.setView(view); - builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { + builder.setPositiveButton(R.string.dialog_positive, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { int sid = SourceManager.getId(editText.getText().toString()); diff --git a/app/src/main/res/layout/custom_back_btn.xml b/app/src/main/res/layout/custom_back_btn.xml index d8000385..8b5c7bc8 100644 --- a/app/src/main/res/layout/custom_back_btn.xml +++ b/app/src/main/res/layout/custom_back_btn.xml @@ -7,7 +7,7 @@ android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:visibility="invisible" - android:background="@color/trans_grey"> + android:background="@color/trans_light_black"> \ No newline at end of file + android:background="@color/trans_black"/> \ No newline at end of file diff --git a/app/src/main/res/layout/custom_seek_bar.xml b/app/src/main/res/layout/custom_seek_bar.xml index 8a8df503..12bebae4 100644 --- a/app/src/main/res/layout/custom_seek_bar.xml +++ b/app/src/main/res/layout/custom_seek_bar.xml @@ -8,8 +8,8 @@ android:layout_alignParentBottom="true" android:visibility="gone" android:padding="8dp" - android:background="@color/trans_grey"> - + + + + + + diff --git a/app/src/main/res/layout/item_picture.xml b/app/src/main/res/layout/item_picture.xml index d71c7ee4..053d1de9 100644 --- a/app/src/main/res/layout/item_picture.xml +++ b/app/src/main/res/layout/item_picture.xml @@ -2,7 +2,7 @@ - - 0 - 1 - 2 - 3 - 4 - 100 - 101 - Cimoc 我的漫画 diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index d9103e36..879d98dd 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -15,5 +15,4 @@ #FFFFFFFF #90000000 #4F000000 - #AA7F7F80 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 05182d14..af4030ec 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -52,6 +52,8 @@ 阅读模式 音量键翻页 仅限翻页模式 + 从右往左翻页 + 默认从左往右 自动切割分页 仅限卷纸模式 其他设置 @@ -64,7 +66,7 @@ 阅读模式选择 文件选择 - version: 1.1.1 + version: 1.2.0 源代码 https://github.com/Arachnid-27/Cimoc 支持作者 From 3a0ad0f52c5fad7eebb32ea93a0bd244dec6bcb1 Mon Sep 17 00:00:00 2001 From: hiroshi Date: Mon, 15 Aug 2016 00:45:28 +0800 Subject: [PATCH 009/521] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=B8=A4=E4=B8=AA?= =?UTF-8?q?=E5=9B=BE=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/dictionaries/Hiroshi.xml | 1 + .../cimoc/core/manager/SourceManager.java | 33 +++++-- .../com/hiroshi/cimoc/core/source/CCTuku.java | 2 +- .../hiroshi/cimoc/core/source/EHentai.java | 3 +- .../hiroshi/cimoc/core/source/NHentai.java | 94 +++++++++++++++++++ .../com/hiroshi/cimoc/core/source/Wnacg.java | 45 +++++---- .../cimoc/presenter/CimocPresenter.java | 6 ++ .../cimoc/presenter/MainPresenter.java | 3 +- .../cimoc/presenter/ReaderPresenter.java | 4 +- .../cimoc/ui/activity/BaseActivity.java | 6 +- .../cimoc/ui/activity/DetailActivity.java | 3 +- .../cimoc/ui/activity/MainActivity.java | 7 +- .../cimoc/ui/activity/PageReaderActivity.java | 60 ++++++------ .../cimoc/ui/activity/ReaderActivity.java | 7 +- .../cimoc/ui/activity/ResultActivity.java | 3 +- .../ui/activity/StreamReaderActivity.java | 4 +- .../cimoc/ui/adapter/PicturePageAdapter.java | 1 - .../cimoc/ui/custom/LimitedViewPager.java | 12 ++- .../cimoc/ui/fragment/CimocFragment.java | 7 +- .../cimoc/utils/ControllerBuilderFactory.java | 6 +- .../com/hiroshi/cimoc/utils/MachiSoup.java | 7 +- .../main/res/layout/activity_page_reader.xml | 2 +- .../res/layout/activity_stream_reader.xml | 2 +- app/src/main/res/layout/item_comic.xml | 1 + app/src/main/res/values/strings.xml | 5 +- 25 files changed, 228 insertions(+), 96 deletions(-) create mode 100644 app/src/main/java/com/hiroshi/cimoc/core/source/NHentai.java diff --git a/.idea/dictionaries/Hiroshi.xml b/.idea/dictionaries/Hiroshi.xml index 956c5907..1e97a5fc 100644 --- a/.idea/dictionaries/Hiroshi.xml +++ b/.idea/dictionaries/Hiroshi.xml @@ -7,6 +7,7 @@ kami machi manhua + nhentai shtml tuku unfavorite diff --git a/app/src/main/java/com/hiroshi/cimoc/core/manager/SourceManager.java b/app/src/main/java/com/hiroshi/cimoc/core/manager/SourceManager.java index de391af0..ff9f7028 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/manager/SourceManager.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/manager/SourceManager.java @@ -10,7 +10,9 @@ import com.hiroshi.cimoc.core.source.ExHentai; import com.hiroshi.cimoc.core.source.HHAAZZ; import com.hiroshi.cimoc.core.source.IKanman; +import com.hiroshi.cimoc.core.source.NHentai; import com.hiroshi.cimoc.core.source.U17; +import com.hiroshi.cimoc.core.source.Wnacg; import com.hiroshi.cimoc.core.source.base.Manga; import com.hiroshi.cimoc.model.Source; import com.hiroshi.cimoc.model.SourceDao; @@ -82,6 +84,10 @@ public static int getTitle(int id) { return R.string.source_ehentai; case SOURCE_EXHENTAI: return R.string.source_exhentai; + case SOURCE_NHENTAI: + return R.string.source_nhentai; + case SOURCE_WNACG: + return R.string.source_wnacg; } return R.string.common_null; } @@ -102,6 +108,10 @@ public static int getId(String key) { return SOURCE_EHENTAI; case "ExHentai": return SOURCE_EXHENTAI; + case "NHentai": + return SOURCE_NHENTAI; + case "Wnacg": + return SOURCE_WNACG; } return -1; } @@ -120,39 +130,50 @@ public static Manga getManga(int source) { case SOURCE_DMZJ: if (manga == null) { manga = new Dmzj(); - sparseArray.put(SOURCE_IKANMAN, manga); + sparseArray.put(SOURCE_DMZJ, manga); } break; case SOURCE_HHAAZZ: if (manga == null) { manga = new HHAAZZ(); - sparseArray.put(SOURCE_IKANMAN, manga); + sparseArray.put(SOURCE_HHAAZZ, manga); } break; case SOURCE_CCTUKU: if (manga == null) { manga = new CCTuku(); - sparseArray.put(SOURCE_IKANMAN, manga); + sparseArray.put(SOURCE_CCTUKU, manga); } break; case SOURCE_U17: if (manga == null) { manga = new U17(); - sparseArray.put(SOURCE_IKANMAN, manga); + sparseArray.put(SOURCE_U17, manga); } break; case SOURCE_EHENTAI: if (manga == null) { manga = new EHentai(); - sparseArray.put(SOURCE_IKANMAN, manga); + sparseArray.put(SOURCE_EHENTAI, manga); } break; case SOURCE_EXHENTAI: if (manga == null) { manga = new ExHentai(); - sparseArray.put(SOURCE_IKANMAN, manga); + sparseArray.put(SOURCE_EXHENTAI, manga); } break; + case SOURCE_NHENTAI: + if (manga == null) { + manga = new NHentai(); + sparseArray.put(SOURCE_NHENTAI, manga); + } + break; + case SOURCE_WNACG: + if (manga == null) { + manga = new Wnacg(); + sparseArray.put(SOURCE_WNACG, manga); + } } return manga; } diff --git a/app/src/main/java/com/hiroshi/cimoc/core/source/CCTuku.java b/app/src/main/java/com/hiroshi/cimoc/core/source/CCTuku.java index e7ec9469..6f095ec7 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/source/CCTuku.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/source/CCTuku.java @@ -64,7 +64,7 @@ protected List parseInto(String html, Comic comic) { list.add(new Chapter(c_title, c_path)); } - String title = body.text("div.title-banner > div.book-title > h1", 0, -2); + String title = body.text("div.title-banner > div.book-title > h1", 0, -3); Node detail = body.select("div.book > div > div:eq(0)"); String cover = detail.attr("div:eq(0) > a > img", "src"); String update = detail.text("div:eq(1) > div > dl:eq(5) > dd > font", 0, 10); diff --git a/app/src/main/java/com/hiroshi/cimoc/core/source/EHentai.java b/app/src/main/java/com/hiroshi/cimoc/core/source/EHentai.java index 74982050..39a17db5 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/source/EHentai.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/source/EHentai.java @@ -30,9 +30,8 @@ protected Request buildSearchRequest(String keyword, int page) { @Override protected List parseSearch(String html, int page) { Node body = MachiSoup.body(html); - List nodes = body.list("#ig > div > table > tbody > tr"); List list = new LinkedList<>(); - for (Node node : nodes) { + for (Node node : body.list("#ig > div > table > tbody > tr")) { String cid = node.attr("td:eq(1) > table > tbody > tr:eq(0) > td > a", "href"); cid = cid.substring(host.length() + 3, cid.length() - 1); String title = node.text("td:eq(1) > table > tbody > tr:eq(0) > td > a"); diff --git a/app/src/main/java/com/hiroshi/cimoc/core/source/NHentai.java b/app/src/main/java/com/hiroshi/cimoc/core/source/NHentai.java new file mode 100644 index 00000000..5f0c8aa6 --- /dev/null +++ b/app/src/main/java/com/hiroshi/cimoc/core/source/NHentai.java @@ -0,0 +1,94 @@ +package com.hiroshi.cimoc.core.source; + +import com.hiroshi.cimoc.core.manager.SourceManager; +import com.hiroshi.cimoc.core.source.base.Manga; +import com.hiroshi.cimoc.model.Chapter; +import com.hiroshi.cimoc.model.Comic; +import com.hiroshi.cimoc.utils.MachiSoup; + +import java.util.LinkedList; +import java.util.List; + +import okhttp3.Request; + +/** + * Created by Hiroshi on 2016/8/14. + */ +public class NHentai extends Manga { + + + public NHentai() { + super(SourceManager.SOURCE_NHENTAI, "https://nhentai.net"); + } + + @Override + protected Request buildSearchRequest(String keyword, int page) { + String url = host + "/search/?q=" + keyword + "&page=" + page; + return new Request.Builder().url(url).build(); + } + + @Override + protected List parseSearch(String html, int page) { + MachiSoup.Node body = MachiSoup.body(html); + List list = new LinkedList<>(); + for (MachiSoup.Node node : body.list("#content > div.index-container > div > a")) { + String cid = node.attr("href", "/", 2); + String title = node.text("div.caption"); + String author = MachiSoup.match("\\[(.*?)\\]", title, 1); + title = title.replaceFirst("\\[.*?\\]\\s+", ""); + String cover = "https:" + node.attr("img", "src"); + list.add(new Comic(source, cid, title, cover, "", author, true)); + } + return list; + } + + @Override + protected Request buildIntoRequest(String cid) { + String url = host + "/g/" + cid; + return new Request.Builder().url(url).build(); + } + + @Override + protected List parseInto(String html, Comic comic) { + List list = new LinkedList<>(); + MachiSoup.Node doc = MachiSoup.body(html); + list.add(new Chapter("全一话", "")); + + String title = doc.text("#info > h1"); + String intro = doc.text("#info > h2"); + String author = doc.text("#tags > div > span > a[href^=/artist/]"); + String cover = "https:" + doc.attr("#cover > a > img", "src"); + comic.setInfo(title, cover, "", intro, author, true); + + return list; + } + + @Override + protected Request buildBrowseRequest(String cid, String path) { + String url = host + "/g/" + cid; + return new Request.Builder().url(url).build(); + } + + @Override + protected String[] parseBrowse(String html) { + MachiSoup.Node body = MachiSoup.body(html); + List list = body.list("#thumbnail-container > div > a > img"); + String[] array = new String[list.size()]; + for (int i = 0; i != list.size(); ++i) { + String url = "https:" + list.get(i).attr("data-src"); + array[i] = url.replace("t.jpg", ".jpg"); + } + return array; + } + + @Override + protected Request buildCheckRequest(String cid) { + return null; + } + + @Override + protected String parseCheck(String html) { + return null; + } + +} diff --git a/app/src/main/java/com/hiroshi/cimoc/core/source/Wnacg.java b/app/src/main/java/com/hiroshi/cimoc/core/source/Wnacg.java index 020d98e5..e36cd572 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/source/Wnacg.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/source/Wnacg.java @@ -1,7 +1,7 @@ package com.hiroshi.cimoc.core.source; -import com.hiroshi.cimoc.core.source.base.Manga; import com.hiroshi.cimoc.core.manager.SourceManager; +import com.hiroshi.cimoc.core.source.base.Manga; import com.hiroshi.cimoc.model.Chapter; import com.hiroshi.cimoc.model.Comic; import com.hiroshi.cimoc.utils.MachiSoup; @@ -24,7 +24,7 @@ public Wnacg() { @Override protected Request buildSearchRequest(String keyword, int page) { String url = host + "/albums-index-page-" + page + "-sname-" + keyword + ".html"; - return new Request.Builder().url(url).header("Cookie", "ipb_member_id=2145630; ipb_pass_hash=f883b5a9dd10234c9323957b96efbd8e").build(); + return new Request.Builder().url(url).build(); } @Override @@ -34,58 +34,57 @@ protected List parseSearch(String html, int page) { for (MachiSoup.Node node : body.list("#bodywrap > div.grid > div > ul > li")) { String cid = node.attr("div.info > div.title > a", "href", "-|\\.", 3); String title = node.text("div.info > div.title > a"); - String cover = node.attr("div.pic_box > a > img", "src"); - String update = node.text("div.info > div.info_col", 0, 10); - String author = node.text("td:eq(3) > div > a"); - list.add(new Comic(source, cid, title, cover, update, author, true)); + String cover = node.attr("div.pic_box > a > img", "data-original"); + String update = node.text("div.info > div.info_col").trim(); + update = MachiSoup.match("\\d{4}-\\d{2}-\\d{2}", update, 0); + list.add(new Comic(source, cid, title, cover, update, null, true)); } return list; } @Override protected Request buildIntoRequest(String cid) { - String url = host + "/g/" + cid; - return new Request.Builder().url(url).header("Cookie", "s=485adc1edc9d59a6a7d62cd15d1a7a213b333f5cb092bcc2d30c476419fbcb5555f19e27c606df9cdc56737cb920fe0855e9671c7109069401d8ede5b718f522; ipb_member_id=2145630; ipb_pass_hash=f883b5a9dd10234c9323957b96efbd8e; uconfig=ts_l;").build(); + String url = host + "/photos-index-aid-" + cid + ".html"; + return new Request.Builder().url(url).build(); } @Override protected List parseInto(String html, Comic comic) { List list = new LinkedList<>(); MachiSoup.Node body = MachiSoup.body(html); - String length = body.text("#gdd > table > tbody > tr:eq(5) > td:eq(1)", " ", 0); - int size = Integer.parseInt(length) % 20 == 0 ? Integer.parseInt(length) / 20 : Integer.parseInt(length) / 20 + 1; - for (int i = 0; i != size; ++i) { + String length = body.text("#bodywrap > div > div.uwconn > label:eq(1)", 3, -2); + int size = Integer.parseInt(length) % 12 == 0 ? Integer.parseInt(length) / 12 : Integer.parseInt(length) / 12 + 1; + for (int i = 1; i <= size; ++i) { list.add(0, new Chapter("Ch" + i, String.valueOf(i))); } - String update = body.text("#gdd > table > tbody > tr:eq(0) > td:eq(1)", 0, 10); - String title = body.text("#gn"); - String intro = body.text("#gj"); - String author = body.text("#taglist > table > tbody > tr > td:eq(1) > div > a[id^=ta_artist]"); - String cover = body.attr("#gd1 > img", "src"); - comic.setInfo(title, cover, update, intro, author, true); + String title = body.text("#bodywrap > h2"); + String intro = body.text("#bodywrap > div > div.uwconn > p", 3); + String author = body.text("#bodywrap > div > div.uwuinfo > p"); + String cover = body.attr("#bodywrap > div > div.uwthumb > img", "data-original"); + comic.setInfo(title, cover, "", intro, author, true); return list; } @Override protected Request buildBrowseRequest(String cid, String path) { - String url = host + "/g/" + cid + "?p=" + path; - return new Request.Builder().url(url).header("Cookie", "s=485adc1edc9d59a6a7d62cd15d1a7a213b333f5cb092bcc2d30c476419fbcb5555f19e27c606df9cdc56737cb920fe0855e9671c7109069401d8ede5b718f522; ipb_member_id=2145630; ipb_pass_hash=f883b5a9dd10234c9323957b96efbd8e; uconfig=ts_l").build(); + String url = host + "/photos-index-page-" + path + "-aid-" + cid + ".html"; + return new Request.Builder().url(url).build(); } @Override protected String[] parseBrowse(String html) { MachiSoup.Node body = MachiSoup.body(html); - List list = body.list("#gdt > div > a"); + List list = body.list("#bodywrap > div.grid > div > ul > li > div.pic_box > a"); String[] array = new String[list.size()]; for (int i = 0; i != array.length; ++i) { - String url = list.get(i).attr("href"); - Request request = new Request.Builder().url(url).header("Cookie", "ipb_member_id=2145630; ipb_pass_hash=f883b5a9dd10234c9323957b96efbd8e").build(); + String url = host + list.get(i).attr("href"); + Request request = new Request.Builder().url(url).build(); String result = execute(request); if (result != null) { MachiSoup.Node node = MachiSoup.body(result); - array[i] = node.attr("#img", "src"); + array[i] = node.attr("#picarea", "src"); } else { array[i] = null; } diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/CimocPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/CimocPresenter.java index 1fe5bcd8..4a2a141b 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/CimocPresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/CimocPresenter.java @@ -34,6 +34,12 @@ public String[] getItems() { } public int getSid(int location) { + if (mSourceList == null) { + getItems(); + } + if (mSourceList.isEmpty()) { + return -1; + } return mSourceList.get(location).getSid(); } diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/MainPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/MainPresenter.java index 1066477e..51d8f2f4 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/MainPresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/MainPresenter.java @@ -108,8 +108,9 @@ public void transFragment() { mMainActivity.hideProgressBar(); } - public boolean onNavigationItemSelected(MenuItem menuItem) { + public boolean switchItem(MenuItem menuItem) { if (menuItem.getItemId() == mCheckedItem) { + mMainActivity.closeDrawer(); return false; } mCheckedItem = menuItem.getItemId(); diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/ReaderPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/ReaderPresenter.java index 7bb8f7b2..1201d983 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/ReaderPresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/ReaderPresenter.java @@ -93,7 +93,7 @@ public void loadPrev() { } } - public void onChapterToNext() { + public void toNextChapter() { Chapter chapter = mPreloadAdapter.nextChapter(); if (chapter == null) { return; @@ -101,7 +101,7 @@ public void onChapterToNext() { switchChapter(1, chapter.getCount(), chapter.getTitle(), chapter.getPath()); } - public void onChapterToPrev() { + public void toPrevChapter() { Chapter chapter = mPreloadAdapter.prevChapter(); if (chapter == null) { return; diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/BaseActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/BaseActivity.java index d8f1c50b..16277fe1 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/BaseActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/BaseActivity.java @@ -9,8 +9,8 @@ import com.hiroshi.cimoc.CimocApplication; import com.hiroshi.cimoc.R; -import com.hiroshi.cimoc.presenter.BasePresenter; import com.hiroshi.cimoc.core.PreferenceMaster; +import com.hiroshi.cimoc.presenter.BasePresenter; import butterknife.ButterKnife; @@ -29,7 +29,7 @@ protected void onCreate(Bundle savedInstanceState) { setContentView(getLayoutRes()); ButterKnife.bind(this); initToolbar(); - initPresenter(savedInstanceState); + initPresenter(); initView(); if (getPresenter() != null) { getPresenter().onCreate(); @@ -78,7 +78,7 @@ protected BasePresenter getPresenter() { return null; } - protected void initPresenter(Bundle savedInstanceState) {} + protected void initPresenter() {} protected void initView() {} diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/DetailActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/DetailActivity.java index f95b6cb3..12d02cd9 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/DetailActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/DetailActivity.java @@ -2,7 +2,6 @@ import android.content.Context; import android.content.Intent; -import android.os.Bundle; import android.support.design.widget.CoordinatorLayout; import android.support.design.widget.FloatingActionButton; import android.support.v7.widget.GridLayoutManager; @@ -60,7 +59,7 @@ public void onClick(View v) { } @Override - protected void initPresenter(Bundle savedInstanceState) { + protected void initPresenter() { long id = getIntent().getLongExtra(EXTRA_ID, -1); int source = getIntent().getIntExtra(EXTRA_SOURCE, -1); String cid = getIntent().getStringExtra(EXTRA_CID); diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/MainActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/MainActivity.java index ceeb372d..47703d1b 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/MainActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/MainActivity.java @@ -1,7 +1,6 @@ package com.hiroshi.cimoc.ui.activity; import android.content.Intent; -import android.os.Bundle; import android.support.design.widget.NavigationView; import android.support.v4.view.GravityCompat; import android.support.v4.widget.DrawerLayout; @@ -14,9 +13,9 @@ import com.hiroshi.cimoc.CimocApplication; import com.hiroshi.cimoc.R; +import com.hiroshi.cimoc.core.PreferenceMaster; import com.hiroshi.cimoc.presenter.BasePresenter; import com.hiroshi.cimoc.presenter.MainPresenter; -import com.hiroshi.cimoc.core.PreferenceMaster; import com.hiroshi.cimoc.utils.DialogFactory; import butterknife.BindView; @@ -75,13 +74,13 @@ public void onDrawerClosed(View drawerView) { mNavigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() { @Override public boolean onNavigationItemSelected(MenuItem item) { - return mPresenter.onNavigationItemSelected(item); + return mPresenter.switchItem(item); } }); } @Override - protected void initPresenter(Bundle savedInstanceState) { + protected void initPresenter() { int home = CimocApplication.getPreferences().getInt(PreferenceMaster.PREF_HOME, PreferenceMaster.HOME_CIMOC); mPresenter = new MainPresenter(this, PreferenceMaster.getHomeId(home)); } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/PageReaderActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/PageReaderActivity.java index adb8dd36..a83868d7 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/PageReaderActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/PageReaderActivity.java @@ -29,7 +29,7 @@ public class PageReaderActivity extends ReaderActivity implements OnPageChangeLi private PicturePageAdapter mPageAdapter; private boolean volume; - private boolean isReverse; + private boolean reverse; @Override public boolean onKeyDown(int keyCode, KeyEvent event) { @@ -50,14 +50,16 @@ public boolean onKeyDown(int keyCode, KeyEvent event) { protected void initView() { if (shouldCreate()) { super.initView(); - isReverse = CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_REVERSE, false); - mSeekBar.setReverse(isReverse); + reverse = CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_REVERSE, false); + mSeekBar.setReverse(reverse); volume = CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_VOLUME, false); mPageAdapter = new PicturePageAdapter(new LinkedList(), getLayoutInflater(), ControllerBuilderFactory.getControllerBuilder(source, this), this); + int current = reverse ? PicturePageAdapter.MAX_COUNT / 2 : PicturePageAdapter.MAX_COUNT / 2 + 1; + mPageAdapter.setCurrent(current); mViewPager.addOnPageChangeListener(this); mViewPager.setAdapter(mPageAdapter); - mViewPager.setCurrentItem(PicturePageAdapter.MAX_COUNT / 2 + 1, false); + mViewPager.setCurrentItem(current, false); mViewPager.setOffscreenPageLimit(3); } } @@ -79,22 +81,14 @@ public void onPageSelected(int position) { } else { mViewPager.setLimit(LimitedViewPager.LIMIT_NONE); } - if (isReverse) { - if (position < current && progress == max) { - mPresenter.onChapterToNext(); - } else if (position > current && progress == 1) { - mPresenter.onChapterToPrev(); - } else { - setReadProgress(progress + current - position); - } + if (progress == max && (position < current && reverse || position > current && !reverse)) { + mPresenter.toNextChapter(); + } else if (progress == 1 && (position > current && reverse || position < current && !reverse)) { + mPresenter.toPrevChapter(); + } else if (reverse) { + setReadProgress(progress + current - position); } else { - if (position > current && progress == max) { - mPresenter.onChapterToNext(); - } else if (position < current && progress == 1) { - mPresenter.onChapterToPrev(); - } else { - setReadProgress(progress + position - current); - } + setReadProgress(progress + position - current); } } @@ -105,8 +99,10 @@ public void onPageScrollStateChanged(int state) { hideToolLayout(); break; case ViewPager.SCROLL_STATE_IDLE: - if (isReverse && mPageAdapter.isToLeft() || !isReverse && mPageAdapter.isToRight()) { + if (reverse && mPageAdapter.isToLeft() || !reverse && mPageAdapter.isToRight()) { mPresenter.loadNext(); + } else if (reverse && mPageAdapter.isToRight() || !reverse && mPageAdapter.isToLeft()) { + mPresenter.loadPrev(); } break; } @@ -115,7 +111,7 @@ public void onPageScrollStateChanged(int state) { @Override public void onProgressChanged(DiscreteSeekBar seekBar, int value, boolean fromUser) { if (fromUser) { - int offset = isReverse ? progress - value : value - progress; + int offset = reverse ? progress - value : value - progress; mViewPager.setCurrentItem(mPageAdapter.getCurrent() + offset); } } @@ -136,7 +132,7 @@ public void onSingleTap(PhotoDraweeView draweeView, float x, float y) { switchToolLayout(); } else if (y >= limitY) { draweeView.retry(); - } else if (!isReverse && mPageAdapter.isToLeft() || isReverse && mPageAdapter.isToRight()) { + } else if (!reverse && mPageAdapter.isToLeft() || reverse && mPageAdapter.isToRight()) { mPresenter.loadPrev(); } } @@ -148,7 +144,7 @@ protected int getLayoutRes() { @Override public void setPrevImage(String[] array) { - if (isReverse) { + if (reverse) { int size = array.length; for (int i = 0; i != size / 2; ++i) { String temp = array[i]; @@ -163,7 +159,7 @@ public void setPrevImage(String[] array) { @Override public void setNextImage(String[] array) { - if (isReverse) { + if (reverse) { int size = array.length; for (int i = 0; i != size / 2; ++i) { String temp = array[i]; @@ -178,8 +174,8 @@ public void setNextImage(String[] array) { @Override public void loadSuccess(boolean isNext) { - if (!isReverse && (isNext && mPageAdapter.isToRight() || !isNext && mPageAdapter.isToLeft()) - || isReverse && (isNext && mPageAdapter.isToLeft() || !isNext && mPageAdapter.isToRight())) { + if (!reverse && (isNext && mViewPager.limitLeft() || !isNext && mViewPager.limitRight()) + || reverse && (isNext && mViewPager.limitRight() || !isNext && mViewPager.limitLeft())) { mViewPager.setLimit(LimitedViewPager.LIMIT_NONE); } showToast(R.string.reader_load_success); @@ -189,19 +185,17 @@ public void loadSuccess(boolean isNext) { public void initLoad(int progress, int max, String title) { super.initLoad(progress, max, title); if (progress != 1) { - if (isReverse) { - mViewPager.setCurrentItem(PicturePageAdapter.MAX_COUNT / 2 + progress); - } else { + if (reverse) { mViewPager.setCurrentItem(PicturePageAdapter.MAX_COUNT / 2 - progress + 1); + } else { + mViewPager.setCurrentItem(PicturePageAdapter.MAX_COUNT / 2 + progress); } } else { - if (mPageAdapter.isToBoth()) { + if (max == 1) { mViewPager.setLimit(LimitedViewPager.LIMIT_BOTH); mPresenter.loadNext(); - } else if (isReverse) { + } else if (reverse) { mViewPager.setLimit(LimitedViewPager.LIMIT_LEFT); - mPageAdapter.setCurrent(PicturePageAdapter.MAX_COUNT / 2); - mViewPager.setCurrentItem(PicturePageAdapter.MAX_COUNT / 2, false); } else { mViewPager.setLimit(LimitedViewPager.LIMIT_RIGHT); } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java index b6108ffa..deaa6884 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java @@ -52,9 +52,7 @@ protected void initView() { if (CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_NIGHT, false)) { mNightMask.setVisibility(View.VISIBLE); } - progress = max = 1; mSeekBar.setOnProgressChangeListener(this); - } @Override @@ -102,7 +100,7 @@ protected BasePresenter getPresenter() { } @Override - protected void initPresenter(Bundle savedInstanceState) { + protected void initPresenter() { if (shouldCreate()) { source = getIntent().getIntExtra(EXTRA_SOURCE, -1); String cid = getIntent().getStringExtra(EXTRA_CID); @@ -161,9 +159,10 @@ public void setReadProgress(int progress) { } public void initLoad(int progress, int max, String title) { - mLoadingLayout.setVisibility(View.INVISIBLE); + this.progress = 1; this.max = max; mChapterTitle.setText(title); + mLoadingLayout.setVisibility(View.INVISIBLE); } public void showToast(int resId) { diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/ResultActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/ResultActivity.java index 1d6d22ee..e7550ebc 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/ResultActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/ResultActivity.java @@ -2,7 +2,6 @@ import android.content.Context; import android.content.Intent; -import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; @@ -35,7 +34,7 @@ public class ResultActivity extends BaseActivity { private ResultPresenter mPresenter; @Override - protected void initPresenter(Bundle savedInstanceState) { + protected void initPresenter() { String keyword = getIntent().getStringExtra(EXTRA_KEYWORD); int source = getIntent().getIntExtra(EXTRA_SOURCE, -1); mPresenter = new ResultPresenter(this, source, keyword); diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/StreamReaderActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/StreamReaderActivity.java index 31ac44ec..e4fc5e73 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/StreamReaderActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/StreamReaderActivity.java @@ -65,13 +65,13 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { position = item; if (dy > 0) { if (progress == max) { - mPresenter.onChapterToNext(); + mPresenter.toNextChapter(); } else { setReadProgress(progress + 1); } } else if (dy < 0) { if (progress == 1) { - mPresenter.onChapterToPrev(); + mPresenter.toPrevChapter(); } else { setReadProgress(progress - 1); } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePageAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePageAdapter.java index 525b1b38..37ca7871 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePageAdapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePageAdapter.java @@ -40,7 +40,6 @@ public PicturePageAdapter(List images, LayoutInflater inflater, Pipeline this.builder = builder; this.listener = listener; this.left = MAX_COUNT / 2; - this.current = MAX_COUNT / 2 + 1; this.right = MAX_COUNT / 2 + 1; } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/custom/LimitedViewPager.java b/app/src/main/java/com/hiroshi/cimoc/ui/custom/LimitedViewPager.java index e0aeacc9..95fd44e8 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/custom/LimitedViewPager.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/custom/LimitedViewPager.java @@ -73,8 +73,16 @@ public void setLimit(int limit) { this.limit = limit; } - public int getLimit() { - return limit; + public boolean limitRight() { + return limit == LIMIT_RIGHT; + } + + public boolean limitLeft() { + return limit == LIMIT_LEFT; + } + + public boolean limitBoth() { + return limit == LIMIT_BOTH; } } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/CimocFragment.java b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/CimocFragment.java index 4c471f64..dbe06295 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/CimocFragment.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/CimocFragment.java @@ -38,7 +38,12 @@ public class CimocFragment extends BaseFragment { if (keyword.isEmpty()) { mInputLayout.setError(getString(R.string.cimoc_empty_error)); } else { - startActivity(ResultActivity.createIntent(getActivity(), keyword, mPresenter.getSid(choice))); + int sid = mPresenter.getSid(choice); + if (sid == -1) { + showSnackbar(R.string.source_source_none); + } else { + startActivity(ResultActivity.createIntent(getActivity(), keyword, mPresenter.getSid(choice))); + } } } diff --git a/app/src/main/java/com/hiroshi/cimoc/utils/ControllerBuilderFactory.java b/app/src/main/java/com/hiroshi/cimoc/utils/ControllerBuilderFactory.java index ffaae41a..dc8c4835 100644 --- a/app/src/main/java/com/hiroshi/cimoc/utils/ControllerBuilderFactory.java +++ b/app/src/main/java/com/hiroshi/cimoc/utils/ControllerBuilderFactory.java @@ -59,7 +59,6 @@ public Response intercept(Chain chain) throws IOException { private static String getReferer(int id) { switch (id) { - default: case SourceManager.SOURCE_IKANMAN: return "http://m.ikanman.com"; case SourceManager.SOURCE_DMZJ: @@ -74,7 +73,12 @@ private static String getReferer(int id) { return "http://lofi.e-hentai.org"; case SourceManager.SOURCE_EXHENTAI: return "https://exhentai.org"; + case SourceManager.SOURCE_NHENTAI: + return "https://nhentai.net"; + case SourceManager.SOURCE_WNACG: + return "http://www.wnacg.com"; } + return ""; } } diff --git a/app/src/main/java/com/hiroshi/cimoc/utils/MachiSoup.java b/app/src/main/java/com/hiroshi/cimoc/utils/MachiSoup.java index e5c41e2f..795fc29c 100644 --- a/app/src/main/java/com/hiroshi/cimoc/utils/MachiSoup.java +++ b/app/src/main/java/com/hiroshi/cimoc/utils/MachiSoup.java @@ -104,14 +104,15 @@ public String text(String cssQuery, int start, int end) { String s = text(cssQuery); if (s == null) { return null; - } else if (end <= 0) { - return s.substring(start, s.length() + end); + } + if (end < 0) { + return s.substring(start, s.length() + 1 + end); } return s.substring(start, end); } public String text(String cssQuery, int start) { - return text(cssQuery, start, 0); + return text(cssQuery, start, -1); } public String text(String cssQuery, String regex, int index) { diff --git a/app/src/main/res/layout/activity_page_reader.xml b/app/src/main/res/layout/activity_page_reader.xml index c19ba99b..e63a7ff5 100644 --- a/app/src/main/res/layout/activity_page_reader.xml +++ b/app/src/main/res/layout/activity_page_reader.xml @@ -41,7 +41,7 @@ android:textColor="@color/white" android:textSize="12sp"/> - + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_stream_reader.xml b/app/src/main/res/layout/activity_stream_reader.xml index e7dc88f3..d8ba4440 100644 --- a/app/src/main/res/layout/activity_stream_reader.xml +++ b/app/src/main/res/layout/activity_stream_reader.xml @@ -40,7 +40,7 @@ android:textColor="@color/white" android:textSize="12sp"/> - + \ No newline at end of file diff --git a/app/src/main/res/layout/item_comic.xml b/app/src/main/res/layout/item_comic.xml index bc7eb3cf..3ea5dfdf 100644 --- a/app/src/main/res/layout/item_comic.xml +++ b/app/src/main/res/layout/item_comic.xml @@ -36,6 +36,7 @@ android:layout_height="wrap_content" android:layout_gravity="center" android:maxLines="1" + android:ellipsize="end" android:textColor="?android:attr/textColorPrimary" android:textSize="12sp"/> 添加图源 图源已存在 添加成功 - 图源错误 + 添加失败 + 未开启图源 看漫画 动漫之家 汗汗漫画 @@ -93,6 +94,8 @@ 有妖气 E-Hentai ExHentai + NHentai + 绅士漫画 网络错误 null From 303d9e0402044c1e0ed5bc1633035f3aa720805d Mon Sep 17 00:00:00 2001 From: hiroshi Date: Tue, 16 Aug 2016 01:32:15 +0800 Subject: [PATCH 010/521] =?UTF-8?q?=E6=9B=BF=E6=8D=A2ViewPager=E4=B8=BARVP?= =?UTF-8?q?=20=E4=BF=AE=E6=AD=A3=E5=B1=8F=E5=B9=95=E5=88=87=E6=8D=A2?= =?UTF-8?q?=E5=BC=95=E5=8F=91=E7=9A=84=E9=97=AE=E9=A2=98=20=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3=E4=B8=80=E5=A4=84=E5=86=85=E5=AD=98=E6=B3=84=E6=BC=8F?= =?UTF-8?q?=20=E5=A2=9E=E5=8A=A0=E7=94=B5=E9=87=8F=E6=98=BE=E7=A4=BA=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=B1=8F=E5=B9=95=E5=B8=B8=E4=BA=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 25 +- .../hiroshi/cimoc/core/PreferenceMaster.java | 1 + .../com/hiroshi/cimoc/core/source/CCTuku.java | 9 +- .../com/hiroshi/cimoc/core/source/Dmzj.java | 11 +- .../hiroshi/cimoc/core/source/EHentai.java | 20 +- .../hiroshi/cimoc/core/source/ExHentai.java | 18 +- .../com/hiroshi/cimoc/core/source/HHAAZZ.java | 9 +- .../hiroshi/cimoc/core/source/IKanman.java | 11 +- .../hiroshi/cimoc/core/source/NHentai.java | 25 +- .../com/hiroshi/cimoc/core/source/U17.java | 15 +- .../com/hiroshi/cimoc/core/source/Wnacg.java | 24 +- .../hiroshi/cimoc/core/source/base/Manga.java | 8 +- .../java/com/hiroshi/cimoc/model/Chapter.java | 6 +- .../com/hiroshi/cimoc/model/EventMessage.java | 17 +- .../cimoc/presenter/ReaderPresenter.java | 17 +- .../cimoc/ui/activity/BaseActivity.java | 6 - .../LandscapeStreamReaderActivity.java | 7 + .../cimoc/ui/activity/PageReaderActivity.java | 178 +++---- .../cimoc/ui/activity/ReaderActivity.java | 120 +++-- .../ui/activity/StreamReaderActivity.java | 129 +++-- .../cimoc/ui/adapter/ChapterAdapter.java | 2 +- .../cimoc/ui/adapter/ComicAdapter.java | 2 +- .../cimoc/ui/adapter/PicturePageAdapter.java | 126 ----- .../ui/adapter/PictureStreamAdapter.java | 129 ----- .../cimoc/ui/adapter/ReaderAdapter.java | 206 ++++++++ .../cimoc/ui/adapter/ResultAdapter.java | 9 +- .../cimoc/ui/custom/LimitedViewPager.java | 88 ---- .../cimoc/ui/custom/MiniClockText.java | 2 +- .../ui/custom/PreCacheLayoutManager.java | 6 +- .../ui/custom/rvp/RecyclerViewPager.java | 448 ++++++++++++++++++ .../custom/rvp/RecyclerViewPagerAdapter.java | 114 +++++ .../cimoc/ui/custom/rvp/ViewUtils.java | 101 ++++ .../cimoc/ui/fragment/SettingsFragment.java | 11 + .../cimoc/utils/ControllerBuilderFactory.java | 24 +- .../main/res/layout/activity_page_reader.xml | 41 +- .../res/layout/activity_stream_reader.xml | 37 +- .../main/res/layout/custom_reader_info.xml | 44 ++ ..._loading.xml => custom_reader_loading.xml} | 0 ...custom_mask.xml => custom_reader_mask.xml} | 0 app/src/main/res/layout/fragment_settings.xml | 32 ++ app/src/main/res/layout/item_result.xml | 7 +- app/src/main/res/values/strings.xml | 6 +- 42 files changed, 1315 insertions(+), 776 deletions(-) create mode 100644 app/src/main/java/com/hiroshi/cimoc/ui/activity/LandscapeStreamReaderActivity.java delete mode 100644 app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePageAdapter.java delete mode 100644 app/src/main/java/com/hiroshi/cimoc/ui/adapter/PictureStreamAdapter.java create mode 100644 app/src/main/java/com/hiroshi/cimoc/ui/adapter/ReaderAdapter.java delete mode 100644 app/src/main/java/com/hiroshi/cimoc/ui/custom/LimitedViewPager.java create mode 100644 app/src/main/java/com/hiroshi/cimoc/ui/custom/rvp/RecyclerViewPager.java create mode 100644 app/src/main/java/com/hiroshi/cimoc/ui/custom/rvp/RecyclerViewPagerAdapter.java create mode 100644 app/src/main/java/com/hiroshi/cimoc/ui/custom/rvp/ViewUtils.java create mode 100644 app/src/main/res/layout/custom_reader_info.xml rename app/src/main/res/layout/{custom_loading.xml => custom_reader_loading.xml} (100%) rename app/src/main/res/layout/{custom_mask.xml => custom_reader_mask.xml} (100%) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e845dbb3..77d0fa2b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -15,7 +15,8 @@ + android:windowSoftInputMode="adjustPan" + android:screenOrientation="portrait"> @@ -23,16 +24,30 @@ + android:name=".ui.activity.ResultActivity" + android:screenOrientation="portrait"/> + android:name=".ui.activity.DetailActivity" + android:screenOrientation="portrait"/> + android:name=".ui.activity.PageReaderActivity" + android:screenOrientation="portrait" + android:configChanges="orientation|screenSize" + android:theme="@style/ReaderTheme"/> + android:name=".ui.activity.StreamReaderActivity" + android:screenOrientation="portrait" + android:configChanges="orientation|screenSize" + android:theme="@style/ReaderTheme"/> + + diff --git a/app/src/main/java/com/hiroshi/cimoc/core/PreferenceMaster.java b/app/src/main/java/com/hiroshi/cimoc/core/PreferenceMaster.java index 9773f675..bb1106d4 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/PreferenceMaster.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/PreferenceMaster.java @@ -24,6 +24,7 @@ public class PreferenceMaster { public static final String PREF_NIGHT = "pref_night"; public static final String PREF_SPLIT = "pref_split"; public static final String PREF_REVERSE = "pref_reverse"; + public static final String PREF_BRIGHT = "pref_bright"; private static final String PREFERENCES_NAME = "cimoc_preferences"; diff --git a/app/src/main/java/com/hiroshi/cimoc/core/source/CCTuku.java b/app/src/main/java/com/hiroshi/cimoc/core/source/CCTuku.java index 6f095ec7..103ae811 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/source/CCTuku.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/source/CCTuku.java @@ -8,6 +8,7 @@ import com.hiroshi.cimoc.utils.MachiSoup; import com.hiroshi.cimoc.utils.MachiSoup.Node; +import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Locale; @@ -83,7 +84,7 @@ protected Request buildBrowseRequest(String cid, String path) { } @Override - protected String[] parseBrowse(String html) { + protected List parseBrowse(String html) { String[] rs = MachiSoup.match("serverUrl = '(.*?)'[\\s\\S]*?eval(.*?)\\n;", html, 1, 2); if (rs != null) { try { @@ -93,11 +94,11 @@ protected String[] parseBrowse(String html) { int tpf = Integer.parseInt(array[1]) + 1; int pages = Integer.parseInt(array[2]); String format = rs[0] + "/" + array[3] + "/" + array[0] + "/%0" + tpf + "d." + array[4]; - String[] images = new String[pages]; + List list = new ArrayList<>(pages); for (int i = 0; i != pages; ++i) { - images[i] = String.format(Locale.CHINA, format, i + 1); + list.add(String.format(Locale.CHINA, format, i + 1)); } - return images; + return list; } } catch (Exception e) { e.printStackTrace(); diff --git a/app/src/main/java/com/hiroshi/cimoc/core/source/Dmzj.java b/app/src/main/java/com/hiroshi/cimoc/core/source/Dmzj.java index b63e69f8..159033e3 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/source/Dmzj.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/source/Dmzj.java @@ -11,6 +11,7 @@ import org.json.JSONObject; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Date; import java.util.LinkedList; import java.util.List; @@ -108,16 +109,16 @@ protected Request buildBrowseRequest(String cid, String path) { } @Override - protected String[] parseBrowse(String html) { + protected List parseBrowse(String html) { String jsonString = MachiSoup.match("\"page_url\":(\\[.*?\\]),", html, 1); if (jsonString != null) { try { JSONArray array = new JSONArray(jsonString); - String[] images = new String[array.length()]; - for (int i = 0; i != images.length; ++i) { - images[i] = array.getString(i); + List list = new ArrayList<>(array.length()); + for (int i = 0; i != array.length(); ++i) { + list.add(array.getString(i)); } - return images; + return list; } catch (Exception e) { e.printStackTrace(); } diff --git a/app/src/main/java/com/hiroshi/cimoc/core/source/EHentai.java b/app/src/main/java/com/hiroshi/cimoc/core/source/EHentai.java index 39a17db5..4c376a93 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/source/EHentai.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/source/EHentai.java @@ -1,12 +1,13 @@ package com.hiroshi.cimoc.core.source; -import com.hiroshi.cimoc.core.source.base.Manga; import com.hiroshi.cimoc.core.manager.SourceManager; +import com.hiroshi.cimoc.core.source.base.Manga; import com.hiroshi.cimoc.model.Chapter; import com.hiroshi.cimoc.model.Comic; import com.hiroshi.cimoc.utils.MachiSoup; import com.hiroshi.cimoc.utils.MachiSoup.Node; +import java.util.ArrayList; import java.util.LinkedList; import java.util.List; @@ -76,22 +77,21 @@ protected Request buildBrowseRequest(String cid, String path) { } @Override - protected String[] parseBrowse(String html) { + protected List parseBrowse(String html) { Node body = MachiSoup.body(html); - List list = body.list("#gh > div > a"); - String[] array = new String[list.size()]; - for (int i = 0; i != list.size(); ++i) { - String url = list.get(i).attr("href"); + List nodes = body.list("#gh > div > a"); + List list = new ArrayList<>(nodes.size()); + for (Node node : nodes) { + String url = node.attr("href"); Request request = new Request.Builder().url(url).build(); String result = execute(request); if (result != null) { - Node node = MachiSoup.body(result); - array[i] = node.attr("#sm", "src"); + list.add(MachiSoup.body(result).attr("#sm", "src")); } else { - array[i] = null; + list.add(null); } } - return array; + return list; } @Override diff --git a/app/src/main/java/com/hiroshi/cimoc/core/source/ExHentai.java b/app/src/main/java/com/hiroshi/cimoc/core/source/ExHentai.java index 5d081a71..15b2e946 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/source/ExHentai.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/source/ExHentai.java @@ -7,6 +7,7 @@ import com.hiroshi.cimoc.utils.MachiSoup; import com.hiroshi.cimoc.utils.MachiSoup.Node; +import java.util.ArrayList; import java.util.LinkedList; import java.util.List; @@ -80,22 +81,21 @@ protected Request buildBrowseRequest(String cid, String path) { } @Override - protected String[] parseBrowse(String html) { + protected List parseBrowse(String html) { Node body = MachiSoup.body(html); - List list = body.list("#gdt > div > a"); - String[] array = new String[list.size()]; - for (int i = 0; i != array.length; ++i) { - String url = list.get(i).attr("href"); + List nodes = body.list("#gdt > div > a"); + List list = new ArrayList<>(nodes.size()); + for (Node node : nodes) { + String url = node.attr("href"); Request request = new Request.Builder().url(url).header("Cookie", "ipb_member_id=2145630; ipb_pass_hash=f883b5a9dd10234c9323957b96efbd8e").build(); String result = execute(request); if (result != null) { - MachiSoup.Node node = MachiSoup.body(result); - array[i] = node.attr("#img", "src"); + list.add(MachiSoup.body(result).attr("#img", "src")); } else { - array[i] = null; + list.add(null); } } - return array; + return list; } @Override diff --git a/app/src/main/java/com/hiroshi/cimoc/core/source/HHAAZZ.java b/app/src/main/java/com/hiroshi/cimoc/core/source/HHAAZZ.java index 001b6eeb..1da7c15d 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/source/HHAAZZ.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/source/HHAAZZ.java @@ -7,6 +7,7 @@ import com.hiroshi.cimoc.utils.MachiSoup; import com.hiroshi.cimoc.utils.MachiSoup.Node; +import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Locale; @@ -84,16 +85,16 @@ protected Request buildBrowseRequest(String cid, String path) { } @Override - protected String[] parseBrowse(String html) { + protected List parseBrowse(String html) { String[] str = MachiSoup.match("sFiles=\"(.*?)\";var sPath=\"(\\d+)\"", html, 1, 2); if (str != null) { String[] result = unsuan(str[0]); String domain = String.format(Locale.CHINA, "http://x8.1112223333.com:9393/dm%02d", Integer.parseInt(str[1])); - String[] array = new String[result.length]; + List list = new ArrayList<>(result.length); for (int i = 0; i != result.length; ++i) { - array[i] = domain + result[i]; + list.add(domain + result[i]); } - return array; + return list; } return null; } diff --git a/app/src/main/java/com/hiroshi/cimoc/core/source/IKanman.java b/app/src/main/java/com/hiroshi/cimoc/core/source/IKanman.java index 06eefe92..8e882e47 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/source/IKanman.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/source/IKanman.java @@ -11,6 +11,7 @@ import org.json.JSONArray; import org.json.JSONObject; +import java.util.ArrayList; import java.util.LinkedList; import java.util.List; @@ -83,7 +84,7 @@ protected Request buildBrowseRequest(String cid, String path) { } @Override - protected String[] parseBrowse(String html) { + protected List parseBrowse(String html) { String str = MachiSoup.match("decryptDES\\(\"(.*?)\"\\)", html, 1); if (str != null) { try { @@ -95,11 +96,11 @@ protected String[] parseBrowse(String html) { String jsonString = result.substring(11, result.length() - 9); JSONObject info = new JSONObject(jsonString); JSONArray array = info.getJSONArray("images"); - String[] images = new String[array.length()]; - for (int i = 0; i != images.length; ++i) { - images[i] = "http://i.hamreus.com:8080" + array.getString(i); + List list = new ArrayList<>(array.length()); + for (int i = 0; i != array.length(); ++i) { + list.add("http://i.hamreus.com:8080" + array.getString(i)); } - return images; + return list; } catch (Exception e) { e.printStackTrace(); } diff --git a/app/src/main/java/com/hiroshi/cimoc/core/source/NHentai.java b/app/src/main/java/com/hiroshi/cimoc/core/source/NHentai.java index 5f0c8aa6..83e185e0 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/source/NHentai.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/source/NHentai.java @@ -5,7 +5,9 @@ import com.hiroshi.cimoc.model.Chapter; import com.hiroshi.cimoc.model.Comic; import com.hiroshi.cimoc.utils.MachiSoup; +import com.hiroshi.cimoc.utils.MachiSoup.Node; +import java.util.ArrayList; import java.util.LinkedList; import java.util.List; @@ -16,7 +18,6 @@ */ public class NHentai extends Manga { - public NHentai() { super(SourceManager.SOURCE_NHENTAI, "https://nhentai.net"); } @@ -29,9 +30,9 @@ protected Request buildSearchRequest(String keyword, int page) { @Override protected List parseSearch(String html, int page) { - MachiSoup.Node body = MachiSoup.body(html); + Node body = MachiSoup.body(html); List list = new LinkedList<>(); - for (MachiSoup.Node node : body.list("#content > div.index-container > div > a")) { + for (Node node : body.list("#content > div.index-container > div > a")) { String cid = node.attr("href", "/", 2); String title = node.text("div.caption"); String author = MachiSoup.match("\\[(.*?)\\]", title, 1); @@ -51,7 +52,7 @@ protected Request buildIntoRequest(String cid) { @Override protected List parseInto(String html, Comic comic) { List list = new LinkedList<>(); - MachiSoup.Node doc = MachiSoup.body(html); + Node doc = MachiSoup.body(html); list.add(new Chapter("全一话", "")); String title = doc.text("#info > h1"); @@ -70,15 +71,15 @@ protected Request buildBrowseRequest(String cid, String path) { } @Override - protected String[] parseBrowse(String html) { - MachiSoup.Node body = MachiSoup.body(html); - List list = body.list("#thumbnail-container > div > a > img"); - String[] array = new String[list.size()]; - for (int i = 0; i != list.size(); ++i) { - String url = "https:" + list.get(i).attr("data-src"); - array[i] = url.replace("t.jpg", ".jpg"); + protected List parseBrowse(String html) { + Node body = MachiSoup.body(html); + List nodes = body.list("#thumbnail-container > div > a > img"); + List list = new ArrayList<>(nodes.size()); + for (Node node : nodes) { + String url = "https:" + node.attr("data-src"); + list.add(url.replace("t.jpg", ".jpg")); } - return array; + return list; } @Override diff --git a/app/src/main/java/com/hiroshi/cimoc/core/source/U17.java b/app/src/main/java/com/hiroshi/cimoc/core/source/U17.java index f69eb237..62a3b52c 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/source/U17.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/source/U17.java @@ -8,6 +8,7 @@ import com.hiroshi.cimoc.utils.MachiSoup; import com.hiroshi.cimoc.utils.MachiSoup.Node; +import java.util.ArrayList; import java.util.LinkedList; import java.util.List; @@ -79,15 +80,15 @@ protected Request buildBrowseRequest(String cid, String path) { } @Override - protected String[] parseBrowse(String html) { - List list = MachiSoup.matchAll("\"src\":\"(.*?)\"", html, 1); - if (!list.isEmpty()) { + protected List parseBrowse(String html) { + List result = MachiSoup.matchAll("\"src\":\"(.*?)\"", html, 1); + if (!result.isEmpty()) { try { - String[] images = new String[list.size()]; - for (int i = 0; i != images.length; ++i) { - images[i] = DecryptionUtils.base64Decrypt(list.get(i)); + List list = new ArrayList<>(result.size()); + for (String str : result) { + list.add(DecryptionUtils.base64Decrypt(str)); } - return images; + return list; } catch (Exception e) { e.printStackTrace(); } diff --git a/app/src/main/java/com/hiroshi/cimoc/core/source/Wnacg.java b/app/src/main/java/com/hiroshi/cimoc/core/source/Wnacg.java index e36cd572..faf5e0aa 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/source/Wnacg.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/source/Wnacg.java @@ -7,6 +7,7 @@ import com.hiroshi.cimoc.utils.MachiSoup; import com.hiroshi.cimoc.utils.MachiSoup.Node; +import java.util.ArrayList; import java.util.LinkedList; import java.util.List; @@ -31,7 +32,7 @@ protected Request buildSearchRequest(String keyword, int page) { protected List parseSearch(String html, int page) { Node body = MachiSoup.body(html); List list = new LinkedList<>(); - for (MachiSoup.Node node : body.list("#bodywrap > div.grid > div > ul > li")) { + for (Node node : body.list("#bodywrap > div.grid > div > ul > li")) { String cid = node.attr("div.info > div.title > a", "href", "-|\\.", 3); String title = node.text("div.info > div.title > a"); String cover = node.attr("div.pic_box > a > img", "data-original"); @@ -51,7 +52,7 @@ protected Request buildIntoRequest(String cid) { @Override protected List parseInto(String html, Comic comic) { List list = new LinkedList<>(); - MachiSoup.Node body = MachiSoup.body(html); + Node body = MachiSoup.body(html); String length = body.text("#bodywrap > div > div.uwconn > label:eq(1)", 3, -2); int size = Integer.parseInt(length) % 12 == 0 ? Integer.parseInt(length) / 12 : Integer.parseInt(length) / 12 + 1; for (int i = 1; i <= size; ++i) { @@ -74,22 +75,21 @@ protected Request buildBrowseRequest(String cid, String path) { } @Override - protected String[] parseBrowse(String html) { - MachiSoup.Node body = MachiSoup.body(html); - List list = body.list("#bodywrap > div.grid > div > ul > li > div.pic_box > a"); - String[] array = new String[list.size()]; - for (int i = 0; i != array.length; ++i) { - String url = host + list.get(i).attr("href"); + protected List parseBrowse(String html) { + Node body = MachiSoup.body(html); + List nodes = body.list("#bodywrap > div.grid > div > ul > li > div.pic_box > a"); + List list = new ArrayList<>(nodes.size()); + for (Node node : nodes) { + String url = host + node.attr("href"); Request request = new Request.Builder().url(url).build(); String result = execute(request); if (result != null) { - MachiSoup.Node node = MachiSoup.body(result); - array[i] = node.attr("#picarea", "src"); + list.add(MachiSoup.body(result).attr("#picarea", "src")); } else { - array[i] = null; + list.add(null); } } - return array; + return list; } @Override diff --git a/app/src/main/java/com/hiroshi/cimoc/core/source/base/Manga.java b/app/src/main/java/com/hiroshi/cimoc/core/source/base/Manga.java index c4fb12d2..31cacbaa 100644 --- a/app/src/main/java/com/hiroshi/cimoc/core/source/base/Manga.java +++ b/app/src/main/java/com/hiroshi/cimoc/core/source/base/Manga.java @@ -70,11 +70,11 @@ public void browse(String cid, String path) { enqueueClient(buildBrowseRequest(cid, path), new OnResponseSuccessHandler() { @Override public void onSuccess(String html) { - String[] images = parseBrowse(html); - if (images == null) { + List list = parseBrowse(html); + if (list == null || list.isEmpty()) { EventBus.getDefault().post(new EventMessage(EventMessage.PARSE_PIC_FAIL, null)); } else { - EventBus.getDefault().post(new EventMessage(EventMessage.PARSE_PIC_SUCCESS, images)); + EventBus.getDefault().post(new EventMessage(EventMessage.PARSE_PIC_SUCCESS, list)); } } }); @@ -140,7 +140,7 @@ protected String execute(Request request) { protected abstract Request buildBrowseRequest(String cid, String path); - protected abstract String[] parseBrowse(String html); + protected abstract List parseBrowse(String html); protected abstract Request buildCheckRequest(String cid); diff --git a/app/src/main/java/com/hiroshi/cimoc/model/Chapter.java b/app/src/main/java/com/hiroshi/cimoc/model/Chapter.java index 0ff9fb6e..d0d4a4a3 100644 --- a/app/src/main/java/com/hiroshi/cimoc/model/Chapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/model/Chapter.java @@ -5,9 +5,9 @@ */ public class Chapter { - String title; - String path; - int count; + private String title; + private String path; + private int count; public Chapter(String title, String path) { this.title = title; diff --git a/app/src/main/java/com/hiroshi/cimoc/model/EventMessage.java b/app/src/main/java/com/hiroshi/cimoc/model/EventMessage.java index 43d0b005..f70985e8 100644 --- a/app/src/main/java/com/hiroshi/cimoc/model/EventMessage.java +++ b/app/src/main/java/com/hiroshi/cimoc/model/EventMessage.java @@ -1,5 +1,10 @@ package com.hiroshi.cimoc.model; +import android.support.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Created by Hiroshi on 2016/7/2. */ @@ -21,22 +26,28 @@ public class EventMessage { public static final int RESTORE_FAVORITE = 14; public static final int COMIC_DELETE = 15; + @IntDef({SEARCH_SUCCESS, SEARCH_FAIL, LOAD_COMIC_SUCCESS, LOAD_COMIC_FAIL, PARSE_PIC_SUCCESS, PARSE_PIC_FAIL, + NETWORK_ERROR, FAVORITE_COMIC, UN_FAVORITE_COMIC, HISTORY_COMIC, COMIC_PAGE_CHANGE, COMIC_LAST_CHANGE, + DELETE_HISTORY, RESTORE_FAVORITE, COMIC_DELETE}) + @Retention(RetentionPolicy.SOURCE) + public @interface EventType {} + private int type; private Object data; private Object second; - public EventMessage(int type, Object data) { + public EventMessage(@EventType int type, Object data) { this.type = type; this.data = data; } - public EventMessage(int type, Object data, Object second) { + public EventMessage(@EventType int type, Object data, Object second) { this.type = type; this.data = data; this.second = second; } - public int getType() { + public @EventType int getType() { return type; } diff --git a/app/src/main/java/com/hiroshi/cimoc/presenter/ReaderPresenter.java b/app/src/main/java/com/hiroshi/cimoc/presenter/ReaderPresenter.java index 1201d983..35dd644f 100644 --- a/app/src/main/java/com/hiroshi/cimoc/presenter/ReaderPresenter.java +++ b/app/src/main/java/com/hiroshi/cimoc/presenter/ReaderPresenter.java @@ -12,6 +12,8 @@ import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; +import java.util.List; + /** * Created by Hiroshi on 2016/7/8. */ @@ -123,31 +125,32 @@ private void switchChapter(int progress, int count, String title, String path) { EventBus.getDefault().post(new EventMessage(EventMessage.COMIC_LAST_CHANGE, path, progress)); } + @SuppressWarnings("unchecked") @Subscribe(threadMode = ThreadMode.MAIN) public void onEvent(EventMessage msg) { switch (msg.getType()) { case EventMessage.PARSE_PIC_SUCCESS: - String[] array = (String[]) msg.getData(); + List list = (List) msg.getData(); Chapter chapter; if (!mPreloadAdapter.isLoad()) { - mReaderActivity.setNextImage(array); + mReaderActivity.setNextImage(list); chapter = mPreloadAdapter.moveNext(); if (!chapter.getPath().equals(last) || page == -1) { page = 1; } - mReaderActivity.initLoad(page, array.length, chapter.getTitle()); + mReaderActivity.initLoad(page, list.size(), chapter.getTitle()); EventBus.getDefault().post(new EventMessage(EventMessage.COMIC_LAST_CHANGE, chapter.getPath(), page)); } else { if (status == LOAD_PREV) { - mReaderActivity.setPrevImage(array); + mReaderActivity.setPrevImage(list); chapter = mPreloadAdapter.movePrev(); } else { - mReaderActivity.setNextImage(array); + mReaderActivity.setNextImage(list); chapter = mPreloadAdapter.moveNext(); } - mReaderActivity.loadSuccess(status == LOAD_NEXT); + mReaderActivity.loadSuccess(); } - chapter.setCount(array.length); + chapter.setCount(list.size()); status = LOAD_NULL; break; case EventMessage.PARSE_PIC_FAIL: diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/BaseActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/BaseActivity.java index 16277fe1..997ed7e2 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/BaseActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/BaseActivity.java @@ -1,6 +1,5 @@ package com.hiroshi.cimoc.ui.activity; -import android.content.pm.ActivityInfo; import android.os.Bundle; import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; @@ -24,7 +23,6 @@ public abstract class BaseActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - initOrientation(); initTheme(); setContentView(getLayoutRes()); ButterKnife.bind(this); @@ -44,10 +42,6 @@ protected void onDestroy() { } } - protected void initOrientation() { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); - } - protected void initTheme() { boolean nightly = CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_NIGHT, false); if (nightly) { diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/LandscapeStreamReaderActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/LandscapeStreamReaderActivity.java new file mode 100644 index 00000000..ce8a28c9 --- /dev/null +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/LandscapeStreamReaderActivity.java @@ -0,0 +1,7 @@ +package com.hiroshi.cimoc.ui.activity; + +/** + * Created by Hiroshi on 2016/8/15. + */ +public class LandscapeStreamReaderActivity extends StreamReaderActivity { +} diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/PageReaderActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/PageReaderActivity.java index a83868d7..cbb3943a 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/PageReaderActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/PageReaderActivity.java @@ -1,32 +1,27 @@ package com.hiroshi.cimoc.ui.activity; import android.graphics.Point; -import android.support.v4.view.ViewPager; -import android.support.v4.view.ViewPager.OnPageChangeListener; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; import android.view.KeyEvent; import com.hiroshi.cimoc.CimocApplication; import com.hiroshi.cimoc.R; import com.hiroshi.cimoc.core.PreferenceMaster; -import com.hiroshi.cimoc.ui.adapter.PicturePageAdapter; -import com.hiroshi.cimoc.ui.custom.LimitedViewPager; import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeView; -import com.hiroshi.cimoc.utils.ControllerBuilderFactory; +import com.hiroshi.cimoc.ui.custom.rvp.RecyclerViewPager; +import com.hiroshi.cimoc.ui.custom.rvp.RecyclerViewPager.OnPageChangedListener; import org.adw.library.widgets.discreteseekbar.DiscreteSeekBar; -import java.util.LinkedList; - import butterknife.BindView; /** * Created by Hiroshi on 2016/7/7. */ -public class PageReaderActivity extends ReaderActivity implements OnPageChangeListener { - - @BindView(R.id.reader_view_pager) LimitedViewPager mViewPager; +public class PageReaderActivity extends ReaderActivity implements OnPageChangedListener { - private PicturePageAdapter mPageAdapter; + @BindView(R.id.reader_recycler_view) RecyclerViewPager mRecyclerView; private boolean volume; private boolean reverse; @@ -36,10 +31,10 @@ public boolean onKeyDown(int keyCode, KeyEvent event) { if (volume) { switch (keyCode) { case KeyEvent.KEYCODE_VOLUME_UP: - mViewPager.prevPage(); + mRecyclerView.scrollToPosition(mRecyclerView.getCurrentPosition() - 1); return true; case KeyEvent.KEYCODE_VOLUME_DOWN: - mViewPager.nextPage(); + mRecyclerView.scrollToPosition(mRecyclerView.getCurrentPosition() + 1); return true; } } @@ -48,71 +43,50 @@ public boolean onKeyDown(int keyCode, KeyEvent event) { @Override protected void initView() { - if (shouldCreate()) { - super.initView(); - reverse = CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_REVERSE, false); - mSeekBar.setReverse(reverse); - volume = CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_VOLUME, false); - mPageAdapter = new PicturePageAdapter(new LinkedList(), getLayoutInflater(), - ControllerBuilderFactory.getControllerBuilder(source, this), this); - int current = reverse ? PicturePageAdapter.MAX_COUNT / 2 : PicturePageAdapter.MAX_COUNT / 2 + 1; - mPageAdapter.setCurrent(current); - mViewPager.addOnPageChangeListener(this); - mViewPager.setAdapter(mPageAdapter); - mViewPager.setCurrentItem(current, false); - mViewPager.setOffscreenPageLimit(3); - } + super.initView(); + reverse = CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_REVERSE, false); + volume = CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_VOLUME, false); + mSeekBar.setReverse(reverse); + mLayoutManager.setExtraSpace(4); + mLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); + mLayoutManager.setReverseLayout(reverse); + mReaderAdapter.setAutoSplit(false); + mRecyclerView.setItemAnimator(null); + mRecyclerView.setLayoutManager(mLayoutManager); + mRecyclerView.setAdapter(mReaderAdapter); + mRecyclerView.addOnPageChangedListener(this); + mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrollStateChanged(RecyclerView recyclerView, int newState) { + switch (newState) { + case RecyclerView.SCROLL_STATE_DRAGGING: + hideToolLayout(); + break; + } + } + }); } @Override - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {} - - @Override - public void onPageSelected(int position) { - int current = mPageAdapter.getCurrent(); - if (position == current) { - return; - } - mPageAdapter.setCurrent(position); - if (mPageAdapter.isToLeft()) { - mViewPager.setLimit(LimitedViewPager.LIMIT_RIGHT); - } else if (mPageAdapter.isToRight()) { - mViewPager.setLimit(LimitedViewPager.LIMIT_LEFT); - } else { - mViewPager.setLimit(LimitedViewPager.LIMIT_NONE); - } - if (progress == max && (position < current && reverse || position > current && !reverse)) { + public void OnPageChanged(int oldPosition, int newPosition) { + if (newPosition > oldPosition && progress == max) { mPresenter.toNextChapter(); - } else if (progress == 1 && (position > current && reverse || position < current && !reverse)) { + } else if (newPosition < oldPosition && progress == 1) { mPresenter.toPrevChapter(); - } else if (reverse) { - setReadProgress(progress + current - position); } else { - setReadProgress(progress + position - current); + setReadProgress(progress + newPosition - oldPosition); } - } - - @Override - public void onPageScrollStateChanged(int state) { - switch (state) { - case ViewPager.SCROLL_STATE_DRAGGING: - hideToolLayout(); - break; - case ViewPager.SCROLL_STATE_IDLE: - if (reverse && mPageAdapter.isToLeft() || !reverse && mPageAdapter.isToRight()) { - mPresenter.loadNext(); - } else if (reverse && mPageAdapter.isToRight() || !reverse && mPageAdapter.isToLeft()) { - mPresenter.loadPrev(); - } - break; + if (newPosition == 0) { + mPresenter.loadPrev(); + } else if (newPosition == mReaderAdapter.getItemCount() - 1) { + mPresenter.loadNext(); } } @Override public void onProgressChanged(DiscreteSeekBar seekBar, int value, boolean fromUser) { if (fromUser) { - int offset = reverse ? progress - value : value - progress; - mViewPager.setCurrentItem(mPageAdapter.getCurrent() + offset); + mRecyclerView.scrollToPosition(mRecyclerView.getCurrentPosition() + value - progress); } } @@ -124,16 +98,26 @@ public void onSingleTap(PhotoDraweeView draweeView, float x, float y) { float limitY = point.y / 3.0f; if (x < limitX) { hideToolLayout(); - mViewPager.prevPage(); + if (mRecyclerView.getCurrentPosition() == 0) { + mPresenter.loadPrev(); + } else if (reverse) { + mRecyclerView.scrollToPosition(mRecyclerView.getCurrentPosition() + 1); + } else { + mRecyclerView.scrollToPosition(mRecyclerView.getCurrentPosition() - 1); + } } else if (x > 2 * limitX) { hideToolLayout(); - mViewPager.nextPage(); + if (mRecyclerView.getCurrentPosition() == mReaderAdapter.getItemCount() - 1) { + mPresenter.loadNext(); + } else if (reverse) { + mRecyclerView.scrollToPosition(mRecyclerView.getCurrentPosition() - 1); + } else { + mRecyclerView.scrollToPosition(mRecyclerView.getCurrentPosition() + 1); + } } else if (y >= 2 * limitY) { switchToolLayout(); } else if (y >= limitY) { draweeView.retry(); - } else if (!reverse && mPageAdapter.isToLeft() || reverse && mPageAdapter.isToRight()) { - mPresenter.loadPrev(); } } @@ -142,65 +126,13 @@ protected int getLayoutRes() { return R.layout.activity_page_reader; } - @Override - public void setPrevImage(String[] array) { - if (reverse) { - int size = array.length; - for (int i = 0; i != size / 2; ++i) { - String temp = array[i]; - array[i] = array[size - i - 1]; - array[size - i - 1] = temp; - } - mPageAdapter.setNextImages(array); - } else { - mPageAdapter.setPrevImages(array); - } - } - - @Override - public void setNextImage(String[] array) { - if (reverse) { - int size = array.length; - for (int i = 0; i != size / 2; ++i) { - String temp = array[i]; - array[i] = array[size - i - 1]; - array[size - i - 1] = temp; - } - mPageAdapter.setPrevImages(array); - } else { - mPageAdapter.setNextImages(array); - } - } - - @Override - public void loadSuccess(boolean isNext) { - if (!reverse && (isNext && mViewPager.limitLeft() || !isNext && mViewPager.limitRight()) - || reverse && (isNext && mViewPager.limitRight() || !isNext && mViewPager.limitLeft())) { - mViewPager.setLimit(LimitedViewPager.LIMIT_NONE); - } - showToast(R.string.reader_load_success); - } - @Override public void initLoad(int progress, int max, String title) { super.initLoad(progress, max, title); if (progress != 1) { - if (reverse) { - mViewPager.setCurrentItem(PicturePageAdapter.MAX_COUNT / 2 - progress + 1); - } else { - mViewPager.setCurrentItem(PicturePageAdapter.MAX_COUNT / 2 + progress); - } + mRecyclerView.scrollToPosition(progress - 1); } else { - if (max == 1) { - mViewPager.setLimit(LimitedViewPager.LIMIT_BOTH); - mPresenter.loadNext(); - } else if (reverse) { - mViewPager.setLimit(LimitedViewPager.LIMIT_LEFT); - } else { - mViewPager.setLimit(LimitedViewPager.LIMIT_RIGHT); - } - String text = progress + "/" + max; - mChapterPage.setText(text); + setReadProgress(1); } } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java index deaa6884..47280e3d 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/ReaderActivity.java @@ -1,11 +1,12 @@ package com.hiroshi.cimoc.ui.activity; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.content.pm.ActivityInfo; +import android.content.IntentFilter; import android.content.res.Configuration; -import android.os.Bundle; import android.view.View; +import android.view.WindowManager; import android.widget.TextView; import android.widget.Toast; @@ -16,12 +17,16 @@ import com.hiroshi.cimoc.model.Comic; import com.hiroshi.cimoc.presenter.BasePresenter; import com.hiroshi.cimoc.presenter.ReaderPresenter; +import com.hiroshi.cimoc.ui.adapter.ReaderAdapter; +import com.hiroshi.cimoc.ui.custom.PreCacheLayoutManager; import com.hiroshi.cimoc.ui.custom.ReverseSeekBar; import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeViewController.OnSingleTapListener; +import com.hiroshi.cimoc.utils.ControllerBuilderFactory; import org.adw.library.widgets.discreteseekbar.DiscreteSeekBar; import org.adw.library.widgets.discreteseekbar.DiscreteSeekBar.OnProgressChangeListener; +import java.util.LinkedList; import java.util.List; import butterknife.BindView; @@ -34,25 +39,41 @@ public abstract class ReaderActivity extends BaseActivity implements OnSingleTap @BindView(R.id.reader_chapter_title) TextView mChapterTitle; @BindView(R.id.reader_chapter_page) TextView mChapterPage; + @BindView(R.id.reader_battery) TextView mBatteryText; @BindView(R.id.reader_progress_layout) View mProgressLayout; @BindView(R.id.reader_back_layout) View mBackLayout; @BindView(R.id.reader_loading_layout) View mLoadingLayout; @BindView(R.id.reader_seek_bar) ReverseSeekBar mSeekBar; @BindView(R.id.reader_mask) View mNightMask; + protected PreCacheLayoutManager mLayoutManager; + protected ReaderAdapter mReaderAdapter; + protected ReaderPresenter mPresenter; - protected int source; protected int progress; protected int max; - private boolean isLandscape; + private int source; @Override protected void initView() { + if (CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_BRIGHT, false)) { + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + } if (CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_NIGHT, false)) { mNightMask.setVisibility(View.VISIBLE); } mSeekBar.setOnProgressChangeListener(this); + mReaderAdapter = new ReaderAdapter(this, new LinkedList()); + mReaderAdapter.setSingleTapListener(this); + mReaderAdapter.setControllerBuilder(ControllerBuilderFactory.getControllerBuilder(source, this)); + mLayoutManager = new PreCacheLayoutManager(this); + } + + @Override + protected void onResume() { + super.onResume(); + registerReceiver(batteryReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); } @Override @@ -61,16 +82,12 @@ protected void onPause() { if (mPresenter != null) { mPresenter.setPage(progress); } + unregisterReceiver(batteryReceiver); } @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - if (mPresenter != null) { - getIntent().putExtra(EXTRA_PAGE, progress); - getIntent().putExtra(EXTRA_POSITION, mPresenter.getChapterPosition()); - getIntent().putExtra(EXTRA_LAST, mPresenter.getCurrentChapter().getPath()); - } + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); } @OnClick(R.id.reader_back_btn) void onBackClick() { @@ -78,22 +95,11 @@ protected void onSaveInstanceState(Bundle outState) { } @Override - protected void initTheme() { - setTheme(R.style.ReaderTheme); - } + protected void initTheme() {} @Override protected void initToolbar() {} - @Override - protected void initOrientation() { - int mode = CimocApplication.getPreferences().getInt(PreferenceMaster.PREF_MODE, PreferenceMaster.MODE_HORIZONTAL_PAGE); - isLandscape = mode == PreferenceMaster.MODE_LANDSCAPE_STREAM; - if (isLandscape) { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); - } - } - @Override protected BasePresenter getPresenter() { return mPresenter; @@ -101,25 +107,15 @@ protected BasePresenter getPresenter() { @Override protected void initPresenter() { - if (shouldCreate()) { - source = getIntent().getIntExtra(EXTRA_SOURCE, -1); - String cid = getIntent().getStringExtra(EXTRA_CID); - String last = getIntent().getStringExtra(EXTRA_LAST); - int page = getIntent().getIntExtra(EXTRA_PAGE, -1); - String[] title = getIntent().getStringArrayExtra(EXTRA_TITLE); - String[] path = getIntent().getStringArrayExtra(EXTRA_PATH); - Chapter[] array = fromArray(title, path); - int position = getIntent().getIntExtra(EXTRA_POSITION, 0); - mPresenter = new ReaderPresenter(this, source, cid, last, page, array, position); - } - } - - protected boolean shouldCreate() { - if (isLandscape) { - return getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; - } else { - return getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT; - } + source = getIntent().getIntExtra(EXTRA_SOURCE, -1); + String cid = getIntent().getStringExtra(EXTRA_CID); + String last = getIntent().getStringExtra(EXTRA_LAST); + int page = getIntent().getIntExtra(EXTRA_PAGE, -1); + String[] title = getIntent().getStringArrayExtra(EXTRA_TITLE); + String[] path = getIntent().getStringArrayExtra(EXTRA_PATH); + Chapter[] array = fromArray(title, path); + int position = getIntent().getIntExtra(EXTRA_POSITION, 0); + mPresenter = new ReaderPresenter(this, source, cid, last, page, array, position); } @Override @@ -128,6 +124,18 @@ public void onStartTrackingTouch(DiscreteSeekBar seekBar) {} @Override public void onStopTrackingTouch(DiscreteSeekBar seekBar) {} + private BroadcastReceiver batteryReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) { + int level = intent.getIntExtra("level", 0); + int scale = intent.getIntExtra("scale", 100); + String text = (level * 100 / scale) + "%"; + mBatteryText.setText(text); + } + } + }; + public void updateChapterInfo(int max, String title) { this.max = max; mChapterTitle.setText(title); @@ -171,11 +179,17 @@ public void showToast(int resId) { } } - public abstract void setPrevImage(String[] array); + public void loadSuccess() { + showToast(R.string.reader_load_success); + } - public abstract void setNextImage(String[] array); + public void setPrevImage(List list) { + mReaderAdapter.addAll(0, list); + } - public abstract void loadSuccess(boolean isNext); + public void setNextImage(List list) { + mReaderAdapter.addAll(list); + } private static final String EXTRA_SOURCE = "a"; private static final String EXTRA_CID = "b"; @@ -219,11 +233,17 @@ private static Chapter[] fromArray(String[] title, String[] path) { public static Intent createIntent(Context context, Comic comic, List list, int position) { int mode = CimocApplication.getPreferences().getInt(PreferenceMaster.PREF_MODE, PreferenceMaster.MODE_HORIZONTAL_PAGE); - Intent intent; - if (mode == PreferenceMaster.MODE_HORIZONTAL_PAGE) { - intent = new Intent(context, PageReaderActivity.class); - } else { - intent = new Intent(context, StreamReaderActivity.class); + Intent intent = null; + switch (mode) { + case PreferenceMaster.MODE_HORIZONTAL_PAGE: + intent = new Intent(context, PageReaderActivity.class); + break; + case PreferenceMaster.MODE_PORTRAIT_STREAM: + intent = new Intent(context, StreamReaderActivity.class); + break; + case PreferenceMaster.MODE_LANDSCAPE_STREAM: + intent = new Intent(context, LandscapeStreamReaderActivity.class); + break; } putExtras(intent, comic, list, position); return intent; diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/activity/StreamReaderActivity.java b/app/src/main/java/com/hiroshi/cimoc/ui/activity/StreamReaderActivity.java index e4fc5e73..045a1a81 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/activity/StreamReaderActivity.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/activity/StreamReaderActivity.java @@ -6,14 +6,12 @@ import com.hiroshi.cimoc.CimocApplication; import com.hiroshi.cimoc.R; import com.hiroshi.cimoc.core.PreferenceMaster; -import com.hiroshi.cimoc.ui.adapter.PictureStreamAdapter; -import com.hiroshi.cimoc.ui.custom.PreCacheLayoutManager; +import com.hiroshi.cimoc.ui.adapter.ReaderAdapter; import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeView; -import com.hiroshi.cimoc.utils.ControllerBuilderFactory; import org.adw.library.widgets.discreteseekbar.DiscreteSeekBar; -import java.util.Arrays; +import java.util.List; import butterknife.BindView; @@ -24,72 +22,64 @@ public class StreamReaderActivity extends ReaderActivity { @BindView(R.id.reader_recycler_view) RecyclerView mRecyclerView; - private PictureStreamAdapter mStreamAdapter; - private PreCacheLayoutManager mLayoutManager; - private int position = 0; @Override protected void initView() { - if (shouldCreate()) { - super.initView(); - boolean split = CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_SPLIT, false); - mLayoutManager = new PreCacheLayoutManager(this); - mLayoutManager.setExtraSpace(8); - mStreamAdapter = new PictureStreamAdapter(this, ControllerBuilderFactory.getControllerBuilder(source, this), this, split); - mRecyclerView.setItemAnimator(null); - mRecyclerView.setLayoutManager(mLayoutManager); - mRecyclerView.setAdapter(mStreamAdapter); - mRecyclerView.addItemDecoration(mStreamAdapter.getItemDecoration()); - mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { - @Override - public void onScrollStateChanged(RecyclerView recyclerView, int newState) { - switch (newState) { - case RecyclerView.SCROLL_STATE_DRAGGING: - hideToolLayout(); - break; - case RecyclerView.SCROLL_STATE_IDLE: - case RecyclerView.SCROLL_STATE_SETTLING: - int item = mLayoutManager.findLastVisibleItemPosition(); - if (item == mStreamAdapter.getItemCount() - 1) { - mPresenter.loadNext(); - } - break; - } + super.initView(); + mLayoutManager.setExtraSpace(6); + mReaderAdapter.setPictureMode(ReaderAdapter.MODE_STREAM); + mReaderAdapter.setAutoSplit(CimocApplication.getPreferences().getBoolean(PreferenceMaster.PREF_SPLIT, false)); + mRecyclerView.setItemAnimator(null); + mRecyclerView.setLayoutManager(mLayoutManager); + mRecyclerView.setAdapter(mReaderAdapter); + mRecyclerView.addItemDecoration(mReaderAdapter.getItemDecoration()); + mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrollStateChanged(RecyclerView recyclerView, int newState) { + switch (newState) { + case RecyclerView.SCROLL_STATE_DRAGGING: + hideToolLayout(); + break; + case RecyclerView.SCROLL_STATE_IDLE: + case RecyclerView.SCROLL_STATE_SETTLING: + int item = mLayoutManager.findLastVisibleItemPosition(); + if (item == mReaderAdapter.getItemCount() - 1) { + mPresenter.loadNext(); + } + break; } - - @Override - public void onScrolled(RecyclerView recyclerView, int dx, int dy) { - int item = mLayoutManager.findFirstVisibleItemPosition(); - if (item != position) { - position = item; - if (dy > 0) { - if (progress == max) { - mPresenter.toNextChapter(); - } else { - setReadProgress(progress + 1); - } - } else if (dy < 0) { - if (progress == 1) { - mPresenter.toPrevChapter(); - } else { - setReadProgress(progress - 1); - } + } + + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + int item = mLayoutManager.findFirstVisibleItemPosition(); + if (item != position) { + if (dy > 0) { + if (progress == max) { + mPresenter.toNextChapter(); } else { - setReadProgress(progress); + setReadProgress(progress + 1); } + } else if (dy < 0) { + if (progress == 1) { + mPresenter.toPrevChapter(); + } else { + setReadProgress(progress - 1); + } + } else { + setReadProgress(progress + item - position); } + position = item; } - }); - } + } + }); } @Override public void onProgressChanged(DiscreteSeekBar seekBar, int value, boolean fromUser) { if (fromUser) { - int offset = value - progress; - progress = value; - mLayoutManager.scrollToPositionWithOffset(position + offset, 0); + mLayoutManager.scrollToPositionWithOffset(position + value - progress, 0); } } @@ -106,34 +96,27 @@ public void onSingleTap(PhotoDraweeView draweeView, float x, float y) { } @Override - protected int getLayoutRes() { - return R.layout.activity_stream_reader; - } - - @Override - public void setPrevImage(String[] array) { - mStreamAdapter.addAll(0, Arrays.asList(array)); - } - - @Override - public void setNextImage(String[] array) { - mStreamAdapter.addAll(Arrays.asList(array)); + public void setPrevImage(List list) { + super.setPrevImage(list); + if (position == 0) { + position = list.size(); + } } @Override - public void loadSuccess(boolean isNext) { - showToast(R.string.reader_load_success); + protected int getLayoutRes() { + return R.layout.activity_stream_reader; } @Override public void initLoad(int progress, int max, String title) { super.initLoad(progress, max, title); - this.progress = progress; if (progress != 1) { + this.progress = progress; + position = progress - 1; mRecyclerView.scrollToPosition(progress - 1); } else { - String text = progress + "/" + max; - mChapterPage.setText(text); + setReadProgress(1); } } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ChapterAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ChapterAdapter.java index fb560c39..cf07c740 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ChapterAdapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ChapterAdapter.java @@ -110,7 +110,7 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (position == 0) { HeaderHolder headerHolder = (HeaderHolder) holder; - PipelineDraweeControllerBuilder builder = ControllerBuilderFactory.getControllerBuilder(source, mContext); + PipelineDraweeControllerBuilder builder = ControllerBuilderFactory.getCoverControllerBuilder(source, mContext); headerHolder.mComicImage.setController(builder.setUri(image).build()); headerHolder.mComicTitle.setText(title); headerHolder.mComicIntro.setText(intro); diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ComicAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ComicAdapter.java index 33654c05..74d22bbb 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ComicAdapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ComicAdapter.java @@ -51,7 +51,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { ViewHolder viewHolder = (ViewHolder) holder; viewHolder.comicTitle.setText(comic.getTitle()); viewHolder.comicSource.setText(SourceManager.getTitle(comic.getSource())); - PipelineDraweeControllerBuilder builder = ControllerBuilderFactory.getControllerBuilder(comic.getSource(), mContext); + PipelineDraweeControllerBuilder builder = ControllerBuilderFactory.getCoverControllerBuilder(comic.getSource(), mContext); viewHolder.comicImage.setController(builder.setUri(comic.getCover()).build()); } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePageAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePageAdapter.java deleted file mode 100644 index 37ca7871..00000000 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PicturePageAdapter.java +++ /dev/null @@ -1,126 +0,0 @@ -package com.hiroshi.cimoc.ui.adapter; - -import android.graphics.drawable.Animatable; -import android.support.v4.view.PagerAdapter; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; - -import com.facebook.drawee.backends.pipeline.PipelineDraweeControllerBuilder; -import com.facebook.drawee.controller.BaseControllerListener; -import com.facebook.imagepipeline.image.ImageInfo; -import com.hiroshi.cimoc.R; -import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeView; -import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeViewController.OnSingleTapListener; - -import java.util.Arrays; -import java.util.List; - -/** - * Created by Hiroshi on 2016/7/7. - */ -public class PicturePageAdapter extends PagerAdapter { - - public static final int MAX_COUNT = 20000; - - private List images; - private LayoutInflater inflater; - private OnSingleTapListener listener; - private PipelineDraweeControllerBuilder builder; - private int left; - private int right; - - private int current; - - public PicturePageAdapter(List images, LayoutInflater inflater, PipelineDraweeControllerBuilder builder, - OnSingleTapListener listener) { - this.images = images; - this.inflater = inflater; - this.builder = builder; - this.listener = listener; - this.left = MAX_COUNT / 2; - this.right = MAX_COUNT / 2 + 1; - } - - public void setCurrent(int current) { - this.current = current; - } - - public int getCurrent() { - return current; - } - - public void setPrevImages(String[] array) { - images.addAll(0, Arrays.asList(array)); - left -= array.length; - notifyDataSetChanged(); - } - - public void setNextImages(String[] array) { - images.addAll(Arrays.asList(array)); - right += array.length; - notifyDataSetChanged(); - } - - public boolean isToBoth() { - return isToLeft() && isToRight(); - } - - public boolean isToLeft() { - return current == left + 1; - } - - public boolean isToRight() { - return current == right - 1; - } - - @Override - public int getItemPosition(Object object) { - View view = (View) object; - return (int) view.getTag(); - } - - @Override - public boolean isViewFromObject(View view, Object object) { - return view == object; - } - - @Override - public int getCount() { - return MAX_COUNT; - } - - @Override - public void destroyItem(ViewGroup container, int position, Object object) { - container.removeView((View) object); - } - - @Override - public Object instantiateItem(ViewGroup container, int position) { - View child = inflater.inflate(R.layout.item_picture, container, false); - if (left < position && position < right) { - final PhotoDraweeView draweeView = (PhotoDraweeView) child.findViewById(R.id.reader_image_view); - draweeView.setScaleType(ImageView.ScaleType.FIT_CENTER); - draweeView.setHorizontalMode(); - draweeView.setOnSingleTapListener(listener); - builder.setControllerListener(new BaseControllerListener() { - @Override - public void onFinalImageSet(String id, ImageInfo imageInfo, Animatable animatable) { - super.onFinalImageSet(id, imageInfo, animatable); - if (imageInfo == null) { - return; - } - draweeView.update(imageInfo.getWidth(), imageInfo.getHeight()); - } - }).setTapToRetryEnabled(true); - draweeView.setController(builder.setUri(images.get(position - left - 1)).build()); - child.setTag(POSITION_UNCHANGED); - } else { - child.setTag(POSITION_NONE); - } - container.addView(child); - return child; - } - -} diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PictureStreamAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PictureStreamAdapter.java deleted file mode 100644 index 354b16f6..00000000 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/PictureStreamAdapter.java +++ /dev/null @@ -1,129 +0,0 @@ -package com.hiroshi.cimoc.ui.adapter; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Rect; -import android.graphics.drawable.Animatable; -import android.net.Uri; -import android.support.v7.widget.RecyclerView; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; - -import com.facebook.common.references.CloseableReference; -import com.facebook.drawee.backends.pipeline.PipelineDraweeControllerBuilder; -import com.facebook.drawee.controller.BaseControllerListener; -import com.facebook.imagepipeline.bitmaps.PlatformBitmapFactory; -import com.facebook.imagepipeline.image.ImageInfo; -import com.facebook.imagepipeline.request.BasePostprocessor; -import com.facebook.imagepipeline.request.ImageRequest; -import com.facebook.imagepipeline.request.ImageRequestBuilder; -import com.hiroshi.cimoc.R; -import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeView; -import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeViewController.OnSingleTapListener; - -import java.util.LinkedList; - -import butterknife.BindView; - -/** - * Created by Hiroshi on 2016/8/5. - */ -public class PictureStreamAdapter extends BaseAdapter { - - private PipelineDraweeControllerBuilder builder; - private OnSingleTapListener listener; - private boolean split; - - public PictureStreamAdapter(Context context, PipelineDraweeControllerBuilder builder, OnSingleTapListener listener, boolean split) { - super(context, new LinkedList()); - this.builder = builder; - this.listener = listener; - this.split = split; - } - - public class ViewHolder extends BaseViewHolder { - @BindView(R.id.reader_image_view) PhotoDraweeView photoView; - - public ViewHolder(View view) { - super(view); - } - } - - @Override - public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - View view = mInflater.inflate(R.layout.item_picture, parent, false); - return new ViewHolder(view); - } - - @Override - public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { - final PhotoDraweeView draweeView = ((ViewHolder) holder).photoView; - draweeView.setId(position); - draweeView.setScaleType(ImageView.ScaleType.CENTER_CROP); - draweeView.setVerticalMode(); - draweeView.setOnSingleTapListener(listener); - builder.setControllerListener(new BaseControllerListener() { - @Override - public void onIntermediateImageSet(String id, ImageInfo imageInfo) { - super.onIntermediateImageSet(id, imageInfo); - if (imageInfo != null) { - draweeView.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT; - draweeView.setAspectRatio((float) imageInfo.getWidth() / imageInfo.getHeight()); - } - } - - @Override - public void onFinalImageSet(String id, ImageInfo imageInfo, Animatable animatable) { - super.onFinalImageSet(id, imageInfo, animatable); - if (imageInfo != null) { - draweeView.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT; - draweeView.setAspectRatio((float) imageInfo.getWidth() / imageInfo.getHeight()); - draweeView.update(imageInfo.getWidth(), imageInfo.getHeight()); - } - } - }).setTapToRetryEnabled(true); - if (split) { - ImageRequest request = ImageRequestBuilder - .newBuilderWithSource(Uri.parse(mDataSet.get(position))) - .setPostprocessor(new SplitPostprocessor()) - .build(); - draweeView.setController(builder.setImageRequest(request).build()); - } else { - draweeView.setController(builder.setUri(mDataSet.get(position)).build()); - } - } - - class SplitPostprocessor extends BasePostprocessor { - @Override - public CloseableReference process(Bitmap sourceBitmap, PlatformBitmapFactory bitmapFactory) { - int width = sourceBitmap.getWidth(); - int height = sourceBitmap.getHeight(); - if (width > 1.2 * height) { - CloseableReference reference = bitmapFactory.createBitmap(width / 2, height * 2, Bitmap.Config.RGB_565); - try { - Bitmap bitmap = reference.get(); - int[] pixels = new int[width * height * 2]; - sourceBitmap.getPixels(pixels, 0, width, width / 2, 0, width / 2, height); - sourceBitmap.getPixels(pixels, width * height, width, 0, 0, width / 2, height); - bitmap.setPixels(pixels, 0, width, 0, 0, width / 2, height * 2); - return CloseableReference.cloneOrNull(reference); - } finally { - CloseableReference.closeSafely(reference); - } - } - return super.process(sourceBitmap, bitmapFactory); - } - } - - @Override - public RecyclerView.ItemDecoration getItemDecoration() { - return new RecyclerView.ItemDecoration() { - @Override - public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { - outRect.set(0, 10, 0, 10); - } - }; - } - -} diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ReaderAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ReaderAdapter.java new file mode 100644 index 00000000..febf80e4 --- /dev/null +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ReaderAdapter.java @@ -0,0 +1,206 @@ +package com.hiroshi.cimoc.ui.adapter; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Rect; +import android.graphics.drawable.Animatable; +import android.net.Uri; +import android.support.annotation.IntDef; +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +import com.facebook.cache.common.CacheKey; +import com.facebook.cache.common.SimpleCacheKey; +import com.facebook.common.references.CloseableReference; +import com.facebook.drawee.backends.pipeline.PipelineDraweeControllerBuilder; +import com.facebook.drawee.controller.BaseControllerListener; +import com.facebook.imagepipeline.bitmaps.PlatformBitmapFactory; +import com.facebook.imagepipeline.image.ImageInfo; +import com.facebook.imagepipeline.request.BasePostprocessor; +import com.facebook.imagepipeline.request.ImageRequest; +import com.facebook.imagepipeline.request.ImageRequestBuilder; +import com.hiroshi.cimoc.R; +import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeView; +import com.hiroshi.cimoc.ui.custom.photo.PhotoDraweeViewController.OnSingleTapListener; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.List; + +import butterknife.BindView; + +/** + * Created by Hiroshi on 2016/8/5. + */ +public class ReaderAdapter extends BaseAdapter { + + public static final int MODE_PAGE = 0; + public static final int MODE_STREAM = 1; + + @IntDef({MODE_PAGE, MODE_STREAM}) + @Retention(RetentionPolicy.SOURCE) + public @interface PictureMode {} + + private PipelineDraweeControllerBuilder builder; + private OnSingleTapListener listener; + private @PictureMode int mode; + private boolean split = false; + + public ReaderAdapter(Context context, List list) { + super(context, list); + } + + public class ViewHolder extends BaseViewHolder { + @BindView(R.id.reader_image_view) PhotoDraweeView photoView; + + public ViewHolder(View view) { + super(view); + } + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view = mInflater.inflate(R.layout.item_picture, parent, false); + return new ViewHolder(view); + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + final PhotoDraweeView draweeView = ((ViewHolder) holder).photoView; + switch (mode) { + case MODE_PAGE: + draweeView.setScaleType(ImageView.ScaleType.FIT_CENTER); + draweeView.setHorizontalMode(); + builder.setControllerListener(new BaseControllerListener() { + @Override + public void onFinalImageSet(String id, ImageInfo imageInfo, Animatable animatable) { + super.onFinalImageSet(id, imageInfo, animatable); + if (imageInfo == null) { + return; + } + draweeView.update(imageInfo.getWidth(), imageInfo.getHeight()); + } + }); + break; + case MODE_STREAM: + draweeView.setScaleType(ImageView.ScaleType.CENTER_CROP); + draweeView.setVerticalMode(); + builder.setControllerListener(new BaseControllerListener() { + @Override + public void onIntermediateImageSet(String id, ImageInfo imageInfo) { + super.onIntermediateImageSet(id, imageInfo); + if (imageInfo != null) { + draweeView.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT; + draweeView.setAspectRatio((float) imageInfo.getWidth() / imageInfo.getHeight()); + } + } + + @Override + public void onFinalImageSet(String id, ImageInfo imageInfo, Animatable animatable) { + super.onFinalImageSet(id, imageInfo, animatable); + if (imageInfo != null) { + draweeView.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT; + draweeView.setAspectRatio((float) imageInfo.getWidth() / imageInfo.getHeight()); + draweeView.update(imageInfo.getWidth(), imageInfo.getHeight()); + } + } + }); + break; + } + draweeView.setOnSingleTapListener(listener); + builder.setTapToRetryEnabled(true); + if (split) { + ImageRequest request = ImageRequestBuilder + .newBuilderWithSource(Uri.parse(mDataSet.get(position))) + .setPostprocessor(new SplitPostprocessor(mDataSet.get(position))) + .build(); + draweeView.setController(builder.setImageRequest(request).build()); + } else { + draweeView.setController(builder.setUri(mDataSet.get(position)).build()); + } + } + + public void setControllerBuilder(PipelineDraweeControllerBuilder builder) { + this.builder = builder; + } + + public void setSingleTapListener(OnSingleTapListener listener) { + this.listener = listener; + } + + public void setAutoSplit(boolean split) { + this.split = split; + } + + public void setPictureMode(@PictureMode int mode) { + this.mode = mode; + } + + class SplitPostprocessor extends BasePostprocessor { + String url; + + public SplitPostprocessor(String url) { + this.url = url; + } + + @Override + public CloseableReference process(Bitmap sourceBitmap, PlatformBitmapFactory bitmapFactory) { + int width = sourceBitmap.getWidth(); + int height = sourceBitmap.getHeight(); + if (width > 1.15 * height) { + CloseableReference reference = bitmapFactory.createBitmap(width / 2, height * 2, Bitmap.Config.RGB_565); + try { + Bitmap bitmap = reference.get(); + int unit = height / 20; + int[] pixels = new int[unit * width]; + int base = 0; + int remain = height - 20 * unit; + for (int i = 1; i >= 0; --i) { + for (int j = 0; j != 20; ++j) { + sourceBitmap.getPixels(pixels, 0, width, i * width / 2, j % 20 * unit, width / 2, unit); + bitmap.setPixels(pixels, 0, width, 0, base + j % 20 * unit, width / 2, unit); + } + if (remain > 0) { + sourceBitmap.getPixels(pixels, 0, width, i * width / 2, 20 * unit, width / 2, remain); + bitmap.setPixels(pixels, 0, width, 0, base + 20 * unit, width / 2, remain); + } + base += height; + } + return CloseableReference.cloneOrNull(reference); + } finally { + CloseableReference.closeSafely(reference); + } + } + return super.process(sourceBitmap, bitmapFactory); + } + + @Override + public CacheKey getPostprocessorCacheKey() { + return new SimpleCacheKey(url + "split"); + } + } + + @Override + public RecyclerView.ItemDecoration getItemDecoration() { + switch (mode) { + default: + case MODE_PAGE: + return new RecyclerView.ItemDecoration() { + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + outRect.set(0, 0, 0, 0); + } + }; + case MODE_STREAM: + return new RecyclerView.ItemDecoration() { + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + outRect.set(0, 10, 0, 10); + } + }; + } + } + +} diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ResultAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ResultAdapter.java index a0f1b93f..6ea38c54 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ResultAdapter.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/adapter/ResultAdapter.java @@ -30,6 +30,7 @@ public class ResultViewHolder extends BaseViewHolder { @BindView(R.id.result_comic_author) TextView comicAuthor; @BindView(R.id.result_comic_update) TextView comicUpdate; @BindView(R.id.result_comic_source) TextView comicSource; + @BindView(R.id.result_comic_update_tab) TextView tabUpdate; public ResultViewHolder(View view) { super(view); @@ -53,8 +54,12 @@ public void onBindViewHolder(ViewHolder holder, int position) { viewHolder.comicTitle.setText(comic.getTitle()); viewHolder.comicAuthor.setText(comic.getAuthor()); viewHolder.comicSource.setText(SourceManager.getTitle(comic.getSource())); - viewHolder.comicUpdate.setText(comic.getUpdate()); - PipelineDraweeControllerBuilder builder = ControllerBuilderFactory.getControllerBuilder(comic.getSource(), mContext); + if (comic.getUpdate().isEmpty()) { + viewHolder.tabUpdate.setVisibility(View.INVISIBLE); + } else { + viewHolder.comicUpdate.setText(comic.getUpdate()); + } + PipelineDraweeControllerBuilder builder = ControllerBuilderFactory.getCoverControllerBuilder(comic.getSource(), mContext); viewHolder.comicImage.setController(builder.setUri(comic.getCover()).build()); } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/custom/LimitedViewPager.java b/app/src/main/java/com/hiroshi/cimoc/ui/custom/LimitedViewPager.java deleted file mode 100644 index 95fd44e8..00000000 --- a/app/src/main/java/com/hiroshi/cimoc/ui/custom/LimitedViewPager.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.hiroshi.cimoc.ui.custom; - -import android.content.Context; -import android.support.v4.view.ViewPager; -import android.util.AttributeSet; -import android.view.MotionEvent; - -/** - * Created by Hiroshi on 2016/7/29. - */ -public class LimitedViewPager extends ViewPager { - - public static final int LIMIT_NONE = 0; - public static final int LIMIT_LEFT = 1; - public static final int LIMIT_RIGHT = 2; - public static final int LIMIT_BOTH = 3; - - private int limit; - - public LimitedViewPager(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public LimitedViewPager(Context context) { - super(context); - } - - private float lastX; - - @Override - public boolean dispatchTouchEvent(MotionEvent ev) { - try { - if (limit == LIMIT_NONE){ - return super.dispatchTouchEvent(ev); - } else if (limit == LIMIT_BOTH) { - return true; - } else { - switch (ev.getAction()) { - case MotionEvent.ACTION_DOWN: - lastX = ev.getX(); - break; - case MotionEvent.ACTION_MOVE: - float value = ev.getX() - lastX; - if (limit == LIMIT_LEFT && value < 0) { - return true; - } - if (limit == LIMIT_RIGHT && value > 0) { - return true; - } - break; - } - return super.dispatchTouchEvent(ev); - } - } catch (IllegalArgumentException e) { - e.printStackTrace(); - } - return false; - } - - public void nextPage() { - if (limit != LIMIT_LEFT && limit != LIMIT_BOTH) { - setCurrentItem(getCurrentItem() + 1); - } - } - - public void prevPage() { - if (limit != LIMIT_RIGHT && limit != LIMIT_BOTH) { - setCurrentItem(getCurrentItem() - 1); - } - } - - public void setLimit(int limit) { - this.limit = limit; - } - - public boolean limitRight() { - return limit == LIMIT_RIGHT; - } - - public boolean limitLeft() { - return limit == LIMIT_LEFT; - } - - public boolean limitBoth() { - return limit == LIMIT_BOTH; - } - -} diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/custom/MiniClockText.java b/app/src/main/java/com/hiroshi/cimoc/ui/custom/MiniClockText.java index 8768c0d8..c3138eda 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/custom/MiniClockText.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/custom/MiniClockText.java @@ -13,7 +13,7 @@ */ public class MiniClockText extends TextView { - public static final CharSequence FORMAT_24_HOUR = "H:mm"; + public static final CharSequence FORMAT_24_HOUR = "HH:mm"; private Calendar mCalendar; private boolean mAttached = false; diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/custom/PreCacheLayoutManager.java b/app/src/main/java/com/hiroshi/cimoc/ui/custom/PreCacheLayoutManager.java index 748684b9..291b0cca 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/custom/PreCacheLayoutManager.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/custom/PreCacheLayoutManager.java @@ -26,7 +26,11 @@ public void setExtraSpace(int extraSpace) { @Override protected int getExtraLayoutSpace(RecyclerView.State state) { if (mExtraSpace > 0) { - return mExtraSpace * getHeight(); + if (getOrientation() == LinearLayoutManager.HORIZONTAL) { + return mExtraSpace * getWidth(); + } else { + return mExtraSpace * getHeight(); + } } return 0; } diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/custom/rvp/RecyclerViewPager.java b/app/src/main/java/com/hiroshi/cimoc/ui/custom/rvp/RecyclerViewPager.java new file mode 100644 index 00000000..74c5135f --- /dev/null +++ b/app/src/main/java/com/hiroshi/cimoc/ui/custom/rvp/RecyclerViewPager.java @@ -0,0 +1,448 @@ +package com.hiroshi.cimoc.ui.custom.rvp; + +import android.content.Context; +import android.graphics.PointF; +import android.os.Build; +import android.os.Parcelable; +import android.support.annotation.NonNull; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.LinearSmoothScroller; +import android.support.v7.widget.RecyclerView; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewTreeObserver; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + +/** + * RecyclerViewPager + * + * @author Green + */ +public class RecyclerViewPager extends RecyclerView { + + private RecyclerViewPagerAdapter mViewPagerAdapter; + private float mTriggerOffset = 0.15f; + private float mFlingFactor = 0.15f; + private float mTouchSpan; + private List mOnPageChangedListeners; + private int mSmoothScrollTargetPosition = -1; + private int mPositionBeforeScroll = -1; + + boolean mNeedAdjust; + int mFirstLeftWhenDragging; + int mFirstTopWhenDragging; + View mCurView; + int mMaxLeftWhenDragging = Integer.MIN_VALUE; + int mMinLeftWhenDragging = Integer.MAX_VALUE; + int mMaxTopWhenDragging = Integer.MIN_VALUE; + int mMinTopWhenDragging = Integer.MAX_VALUE; + private int mPositionOnTouchDown = -1; + private boolean mHasCalledOnPageChanged = true; + private boolean reverseLayout = false; + + public RecyclerViewPager(Context context) { + this(context, null); + } + + public RecyclerViewPager(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public RecyclerViewPager(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + setNestedScrollingEnabled(false); + } + + @Override + protected void onRestoreInstanceState(Parcelable state) { + try { + Field fLayoutState = state.getClass().getDeclaredField("mLayoutState"); + fLayoutState.setAccessible(true); + Object layoutState = fLayoutState.get(state); + Field fAnchorOffset = layoutState.getClass().getDeclaredField("mAnchorOffset"); + Field fAnchorPosition = layoutState.getClass().getDeclaredField("mAnchorPosition"); + fAnchorPosition.setAccessible(true); + fAnchorOffset.setAccessible(true); + if (fAnchorOffset.getInt(layoutState) > 0) { + fAnchorPosition.set(layoutState, fAnchorPosition.getInt(layoutState) - 1); + } else if (fAnchorOffset.getInt(layoutState) < 0) { + fAnchorPosition.set(layoutState, fAnchorPosition.getInt(layoutState) + 1); + } + fAnchorOffset.setInt(layoutState, 0); + } catch (Throwable e) { + e.printStackTrace(); + } + super.onRestoreInstanceState(state); + } + + @Override + public void setAdapter(Adapter adapter) { + mViewPagerAdapter = ensureRecyclerViewPagerAdapter(adapter); + super.setAdapter(mViewPagerAdapter); + } + + @Override + public void swapAdapter(Adapter adapter, boolean removeAndRecycleExistingViews) { + mViewPagerAdapter = ensureRecyclerViewPagerAdapter(adapter); + super.swapAdapter(mViewPagerAdapter, removeAndRecycleExistingViews); + } + + @Override + public Adapter getAdapter() { + if (mViewPagerAdapter != null) { + return mViewPagerAdapter.mAdapter; + } + return null; + } + + public RecyclerViewPagerAdapter getWrapperAdapter() { + return mViewPagerAdapter; + } + + @Override + public void setLayoutManager(LayoutManager layout) { + super.setLayoutManager(layout); + + if (layout instanceof LinearLayoutManager) { + reverseLayout = ((LinearLayoutManager) layout).getReverseLayout(); + } + } + + @Override + public boolean fling(int velocityX, int velocityY) { + boolean flinging = super.fling((int) (velocityX * mFlingFactor), (int) (velocityY * mFlingFactor)); + if (flinging) { + if (getLayoutManager().canScrollHorizontally()) { + adjustPositionX(velocityX); + } else { + adjustPositionY(velocityY); + } + } + + return flinging; + } + + @Override + public void smoothScrollToPosition(int position) { + mSmoothScrollTargetPosition = position; + if (getLayoutManager() != null && getLayoutManager() instanceof LinearLayoutManager) { + // exclude item decoration + LinearSmoothScroller linearSmoothScroller = + new LinearSmoothScroller(getContext()) { + @Override + public PointF computeScrollVectorForPosition(int targetPosition) { + if (getLayoutManager() == null) { + return null; + } + return ((LinearLayoutManager) getLayoutManager()) + .computeScrollVectorForPosition(targetPosition); + } + + @Override + protected void onTargetFound(View targetView, State state, Action action) { + if (getLayoutManager() == null) { + return; + } + int dx = calculateDxToMakeVisible(targetView, + getHorizontalSnapPreference()); + int dy = calculateDyToMakeVisible(targetView, + getVerticalSnapPreference()); + if (dx > 0) { + dx = dx - getLayoutManager() + .getLeftDecorationWidth(targetView); + } else { + dx = dx + getLayoutManager() + .getRightDecorationWidth(targetView); + } + if (dy > 0) { + dy = dy - getLayoutManager() + .getTopDecorationHeight(targetView); + } else { + dy = dy + getLayoutManager() + .getBottomDecorationHeight(targetView); + } + final int distance = (int) Math.sqrt(dx * dx + dy * dy); + final int time = calculateTimeForDeceleration(distance); + if (time > 0) { + action.update(-dx, -dy, time, mDecelerateInterpolator); + } + } + }; + linearSmoothScroller.setTargetPosition(position); + if (position == RecyclerView.NO_POSITION) { + return; + } + getLayoutManager().startSmoothScroll(linearSmoothScroller); + } else { + super.smoothScrollToPosition(position); + } + } + + @Override + public void scrollToPosition(int position) { + mPositionBeforeScroll = getCurrentPosition(); + mSmoothScrollTargetPosition = position; + super.scrollToPosition(position); + + getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + @SuppressWarnings("deprecation") + @Override + public void onGlobalLayout() { + if (Build.VERSION.SDK_INT < 16) { + getViewTreeObserver().removeGlobalOnLayoutListener(this); + } else { + getViewTreeObserver().removeOnGlobalLayoutListener(this); + } + + if (mSmoothScrollTargetPosition >= 0 && mSmoothScrollTargetPosition < getItemCount()) { + if (mOnPageChangedListeners != null) { + for (OnPageChangedListener onPageChangedListener : mOnPageChangedListeners) { + if (onPageChangedListener != null) { + onPageChangedListener.OnPageChanged(mPositionBeforeScroll, getCurrentPosition()); + } + } + } + } + } + }); + } + + private int getItemCount() { + return mViewPagerAdapter == null ? 0 : mViewPagerAdapter.getItemCount(); + } + + /** + * get item position in center of viewpager + */ + public int getCurrentPosition() { + int curPosition; + if (getLayoutManager().canScrollHorizontally()) { + curPosition = ViewUtils.getCenterXChildPosition(this); + } else { + curPosition = ViewUtils.getCenterYChildPosition(this); + } + if (curPosition < 0) { + curPosition = mSmoothScrollTargetPosition; + } + return curPosition; + } + + /*** + * adjust position before Touch event complete and fling action start. + */ + protected void adjustPositionX(int velocityX) { + if (reverseLayout) velocityX *= -1; + + int childCount = getChildCount(); + if (childCount > 0) { + int curPosition = ViewUtils.getCenterXChildPosition(this); + int childWidth = getWidth() - getPaddingLeft() - getPaddingRight(); + int flingCount = Math.max(-1, Math.min(1, getFlingCount(velocityX, childWidth))); + int targetPosition = flingCount == 0 ? curPosition : mPositionOnTouchDown + flingCount; + targetPosition = Math.max(targetPosition, 0); + targetPosition = Math.min(targetPosition, getItemCount() - 1); + if (targetPosition == curPosition && mPositionOnTouchDown == curPosition) { + View centerXChild = ViewUtils.getCenterXChild(this); + if (centerXChild != null) { + if (mTouchSpan > centerXChild.getWidth() * mTriggerOffset * mTriggerOffset && targetPosition != 0) { + if (!reverseLayout) targetPosition--; + else targetPosition++; + } else if (mTouchSpan < centerXChild.getWidth() * -mTriggerOffset && targetPosition != getItemCount() - 1) { + if (!reverseLayout) targetPosition++; + else targetPosition--; + } + } + } + smoothScrollToPosition(safeTargetPosition(targetPosition, getItemCount())); + } + } + + public void addOnPageChangedListener(OnPageChangedListener listener) { + if (mOnPageChangedListeners == null) { + mOnPageChangedListeners = new ArrayList<>(); + } + mOnPageChangedListeners.add(listener); + } + + public void removeOnPageChangedListener(OnPageChangedListener listener) { + if (mOnPageChangedListeners != null) { + mOnPageChangedListeners.remove(listener); + } + } + + public void clearOnPageChangedListeners() { + if (mOnPageChangedListeners != null) { + mOnPageChangedListeners.clear(); + } + } + + /*** + * adjust position before Touch event complete and fling action start. + */ + protected void adjustPositionY(int velocityY) { + if (reverseLayout) velocityY *= -1; + + int childCount = getChildCount(); + if (childCount > 0) { + int curPosition = ViewUtils.getCenterYChildPosition(this); + int childHeight = getHeight() - getPaddingTop() - getPaddingBottom(); + int flingCount = Math.max(-1, Math.min(1, getFlingCount(velocityY, childHeight))); + int targetPosition = flingCount == 0 ? curPosition : mPositionOnTouchDown + flingCount; + targetPosition = Math.max(targetPosition, 0); + targetPosition = Math.min(targetPosition, getItemCount() - 1); + if (targetPosition == curPosition && mPositionOnTouchDown == curPosition) { + View centerYChild = ViewUtils.getCenterYChild(this); + if (centerYChild != null) { + if (mTouchSpan > centerYChild.getHeight() * mTriggerOffset && targetPosition != 0) { + if (!reverseLayout) targetPosition--; + else targetPosition++; + } else if (mTouchSpan < centerYChild.getHeight() * -mTriggerOffset && targetPosition != getItemCount() - 1) { + if (!reverseLayout) targetPosition++; + else targetPosition--; + } + } + } + smoothScrollToPosition(safeTargetPosition(targetPosition, getItemCount())); + } + } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if (ev.getAction() == MotionEvent.ACTION_DOWN && getLayoutManager() != null) { + mPositionOnTouchDown = getLayoutManager().canScrollHorizontally() + ? ViewUtils.getCenterXChildPosition(this) + : ViewUtils.getCenterYChildPosition(this); + } + return super.dispatchTouchEvent(ev); + } + + @Override + public boolean onTouchEvent(MotionEvent e) { + // recording the max/min value in touch track + if (e.getAction() == MotionEvent.ACTION_MOVE) { + if (mCurView != null) { + mMaxLeftWhenDragging = Math.max(mCurView.getLeft(), mMaxLeftWhenDragging); + mMaxTopWhenDragging = Math.max(mCurView.getTop(), mMaxTopWhenDragging); + mMinLeftWhenDragging = Math.min(mCurView.getLeft(), mMinLeftWhenDragging); + mMinTopWhenDragging = Math.min(mCurView.getTop(), mMinTopWhenDragging); + } + } + return super.onTouchEvent(e); + } + + @Override + public void onScrollStateChanged(int state) { + super.onScrollStateChanged(state); + if (state == SCROLL_STATE_DRAGGING) { + mNeedAdjust = true; + mCurView = getLayoutManager().canScrollHorizontally() ? ViewUtils.getCenterXChild(this) : + ViewUtils.getCenterYChild(this); + if (mCurView != null) { + if (mHasCalledOnPageChanged) { + // While rvp is scrolling, mPositionBeforeScroll will be previous value. + mPositionBeforeScroll = getChildLayoutPosition(mCurView); + mHasCalledOnPageChanged = false; + } + mFirstLeftWhenDragging = mCurView.getLeft(); + mFirstTopWhenDragging = mCurView.getTop(); + } else { + mPositionBeforeScroll = -1; + } + mTouchSpan = 0; + } else if (state == SCROLL_STATE_SETTLING) { + mNeedAdjust = false; + if (mCurView != null) { + if (getLayoutManager().canScrollHorizontally()) { + mTouchSpan = mCurView.getLeft() - mFirstLeftWhenDragging; + } else { + mTouchSpan = mCurView.getTop() - mFirstTopWhenDragging; + } + } else { + mTouchSpan = 0; + } + mCurView = null; + } else if (state == SCROLL_STATE_IDLE) { + if (mNeedAdjust) { + int targetPosition = getLayoutManager().canScrollHorizontally() ? ViewUtils.getCenterXChildPosition(this) : + ViewUtils.getCenterYChildPosition(this); + if (mCurView != null) { + targetPosition = getChildAdapterPosition(mCurView); + if (getLayoutManager().canScrollHorizontally()) { + int spanX = mCurView.getLeft() - mFirstLeftWhenDragging; + // if user is tending to cancel paging action, don't perform position changing + if (spanX > mCurView.getWidth() * mTriggerOffset && mCurView.getLeft() >= mMaxLeftWhenDragging) { + if (!reverseLayout) targetPosition--; + else targetPosition++; + } else if (spanX < mCurView.getWidth() * -mTriggerOffset && mCurView.getLeft() <= mMinLeftWhenDragging) { + if (!reverseLayout) targetPosition++; + else targetPosition--; + } + } else { + int spanY = mCurView.getTop() - mFirstTopWhenDragging; + if (spanY > mCurView.getHeight() * mTriggerOffset && mCurView.getTop() >= mMaxTopWhenDragging) { + if (!reverseLayout) targetPosition--; + else targetPosition++; + } else if (spanY < mCurView.getHeight() * -mTriggerOffset && mCurView.getTop() <= mMinTopWhenDragging) { + if (!reverseLayout) targetPosition++; + else targetPosition--; + } + } + } + smoothScrollToPosition(safeTargetPosition(targetPosition, getItemCount())); + mCurView = null; + } else if (mSmoothScrollTargetPosition != mPositionBeforeScroll) { + if (mOnPageChangedListeners != null) { + for (OnPageChangedListener onPageChangedListener : mOnPageChangedListeners) { + if (onPageChangedListener != null) { + onPageChangedListener.OnPageChanged(mPositionBeforeScroll, mSmoothScrollTargetPosition); + } + } + } + mHasCalledOnPageChanged = true; + mPositionBeforeScroll = mSmoothScrollTargetPosition; + } + // reset + mMaxLeftWhenDragging = Integer.MIN_VALUE; + mMinLeftWhenDragging = Integer.MAX_VALUE; + mMaxTopWhenDragging = Integer.MIN_VALUE; + mMinTopWhenDragging = Integer.MAX_VALUE; + } + } + + @SuppressWarnings("unchecked") + @NonNull + protected RecyclerViewPagerAdapter ensureRecyclerViewPagerAdapter(Adapter adapter) { + return (adapter instanceof RecyclerViewPagerAdapter) + ? (RecyclerViewPagerAdapter) adapter + : new RecyclerViewPagerAdapter(this, adapter); + + } + + private int getFlingCount(int velocity, int cellSize) { + if (velocity == 0) { + return 0; + } + int sign = velocity > 0 ? 1 : -1; + return (int) (sign * Math.ceil((velocity * sign * mFlingFactor / cellSize) + - mTriggerOffset)); + } + + private int safeTargetPosition(int position, int count) { + if (position < 0) { + return 0; + } + if (position >= count) { + return count - 1; + } + return position; + } + + public interface OnPageChangedListener { + void OnPageChanged(int oldPosition, int newPosition); + } + +} diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/custom/rvp/RecyclerViewPagerAdapter.java b/app/src/main/java/com/hiroshi/cimoc/ui/custom/rvp/RecyclerViewPagerAdapter.java new file mode 100644 index 00000000..337c4f41 --- /dev/null +++ b/app/src/main/java/com/hiroshi/cimoc/ui/custom/rvp/RecyclerViewPagerAdapter.java @@ -0,0 +1,114 @@ +package com.hiroshi.cimoc.ui.custom.rvp; + +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.view.ViewGroup; + +/** + * RecyclerViewPagerAdapter
+ * Adapter wrapper. + * + * @author Green + */ +public class RecyclerViewPagerAdapter extends RecyclerView.Adapter { + private final RecyclerViewPager mViewPager; + RecyclerView.Adapter mAdapter; + + + public RecyclerViewPagerAdapter(RecyclerViewPager viewPager, RecyclerView.Adapter adapter) { + mAdapter = adapter; + mViewPager = viewPager; + setHasStableIds(mAdapter.hasStableIds()); + } + + @Override + public VH onCreateViewHolder(ViewGroup parent, int viewType) { + return mAdapter.onCreateViewHolder(parent, viewType); + } + + @Override + public void registerAdapterDataObserver(RecyclerView.AdapterDataObserver observer) { + super.registerAdapterDataObserver(observer); + mAdapter.registerAdapterDataObserver(observer); + } + + @Override + public void unregisterAdapterDataObserver(RecyclerView.AdapterDataObserver observer) { + super.unregisterAdapterDataObserver(observer); + mAdapter.unregisterAdapterDataObserver(observer); + } + + @Override + public void onViewRecycled(VH holder) { + super.onViewRecycled(holder); + mAdapter.onViewRecycled(holder); + } + + @Override + public boolean onFailedToRecycleView(VH holder) { + return mAdapter.onFailedToRecycleView(holder); + } + + @Override + public void onViewAttachedToWindow(VH holder) { + super.onViewAttachedToWindow(holder); + mAdapter.onViewAttachedToWindow(holder); + } + + @Override + public void onViewDetachedFromWindow(VH holder) { + super.onViewDetachedFromWindow(holder); + mAdapter.onViewDetachedFromWindow(holder); + } + + @Override + public void onAttachedToRecyclerView(RecyclerView recyclerView) { + super.onAttachedToRecyclerView(recyclerView); + mAdapter.onAttachedToRecyclerView(recyclerView); + } + + @Override + public void onDetachedFromRecyclerView(RecyclerView recyclerView) { + super.onDetachedFromRecyclerView(recyclerView); + mAdapter.onDetachedFromRecyclerView(recyclerView); + } + + @Override + public void onBindViewHolder(VH holder, int position) { + mAdapter.onBindViewHolder(holder, position); + final View itemView = holder.itemView; + ViewGroup.LayoutParams lp; + if (itemView.getLayoutParams() == null) { + lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + } else { + lp = itemView.getLayoutParams(); + if (mViewPager.getLayoutManager().canScrollHorizontally()) { + lp.width = ViewGroup.LayoutParams.MATCH_PARENT; + } else { + lp.height = ViewGroup.LayoutParams.MATCH_PARENT; + } + } + itemView.setLayoutParams(lp); + } + + @Override + public void setHasStableIds(boolean hasStableIds) { + super.setHasStableIds(hasStableIds); + mAdapter.setHasStableIds(hasStableIds); + } + + @Override + public int getItemCount() { + return mAdapter.getItemCount(); + } + + @Override + public int getItemViewType(int position) { + return mAdapter.getItemViewType(position); + } + + @Override + public long getItemId(int position) { + return mAdapter.getItemId(position); + } +} diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/custom/rvp/ViewUtils.java b/app/src/main/java/com/hiroshi/cimoc/ui/custom/rvp/ViewUtils.java new file mode 100644 index 00000000..26448226 --- /dev/null +++ b/app/src/main/java/com/hiroshi/cimoc/ui/custom/rvp/ViewUtils.java @@ -0,0 +1,101 @@ +package com.hiroshi.cimoc.ui.custom.rvp; + +import android.support.v7.widget.RecyclerView; +import android.view.View; + +public class ViewUtils { + + /** + * Get center child in X Axes + */ + public static View getCenterXChild(RecyclerView recyclerView) { + int childCount = recyclerView.getChildCount(); + if (childCount > 0) { + for (int i = 0; i < childCount; i++) { + View child = recyclerView.getChildAt(i); + if (isChildInCenterX(recyclerView, child)) { + return child; + } + } + } + return null; + } + + /** + * Get position of center child in X Axes + */ + public static int getCenterXChildPosition(RecyclerView recyclerView) { + int childCount = recyclerView.getChildCount(); + if (childCount > 0) { + for (int i = 0; i < childCount; i++) { + View child = recyclerView.getChildAt(i); + if (isChildInCenterX(recyclerView, child)) { + return recyclerView.getChildAdapterPosition(child); + } + } + } + return childCount; + } + + /** + * Get center child in Y Axes + */ + public static View getCenterYChild(RecyclerView recyclerView) { + int childCount = recyclerView.getChildCount(); + if (childCount > 0) { + for (int i = 0; i < childCount; i++) { + View child = recyclerView.getChildAt(i); + if (isChildInCenterY(recyclerView, child)) { + return child; + } + } + } + return null; + } + + /** + * Get position of center child in Y Axes + */ + public static int getCenterYChildPosition(RecyclerView recyclerView) { + int childCount = recyclerView.getChildCount(); + if (childCount > 0) { + for (int i = 0; i < childCount; i++) { + View child = recyclerView.getChildAt(i); + if (isChildInCenterY(recyclerView, child)) { + return recyclerView.getChildAdapterPosition(child); + } + } + } + return childCount; + } + + public static boolean isChildInCenterX(RecyclerView recyclerView, View view) { + int childCount = recyclerView.getChildCount(); + int[] lvLocationOnScreen = new int[2]; + int[] vLocationOnScreen = new int[2]; + recyclerView.getLocationOnScreen(lvLocationOnScreen); + int middleX = lvLocationOnScreen[0] + recyclerView.getWidth() / 2; + if (childCount > 0) { + view.getLocationOnScreen(vLocationOnScreen); + if (vLocationOnScreen[0] <= middleX && vLocationOnScreen[0] + view.getWidth() >= middleX) { + return true; + } + } + return false; + } + + public static boolean isChildInCenterY(RecyclerView recyclerView, View view) { + int childCount = recyclerView.getChildCount(); + int[] lvLocationOnScreen = new int[2]; + int[] vLocationOnScreen = new int[2]; + recyclerView.getLocationOnScreen(lvLocationOnScreen); + int middleY = lvLocationOnScreen[1] + recyclerView.getHeight() / 2; + if (childCount > 0) { + view.getLocationOnScreen(vLocationOnScreen); + if (vLocationOnScreen[1] <= middleY && vLocationOnScreen[1] + view.getHeight() >= middleY) { + return true; + } + } + return false; + } +} diff --git a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SettingsFragment.java b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SettingsFragment.java index fa7ac218..4dcc7fb8 100644 --- a/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SettingsFragment.java +++ b/app/src/main/java/com/hiroshi/cimoc/ui/fragment/SettingsFragment.java @@ -26,6 +26,7 @@ public class SettingsFragment extends BaseFragment { @BindView(R.id.settings_reader_split_checkbox) CheckBox mSplitBox; @BindView(R.id.settings_reader_volume_checkbox) CheckBox mVolumeBox; @BindView(R.id.settings_reader_reverse_checkbox) CheckBox mReverseBox; + @BindView(R.id.settings_reader_bright_checkbox) CheckBox mBrightBox; @BindView(R.id.settings_other_night_checkbox) CheckBox mNightBox; private SettingsPresenter mPresenter; @@ -39,6 +40,7 @@ public class SettingsFragment extends BaseFragment { private boolean mVolumeChoice; private boolean mNightChoice; private boolean mReverseChoice; + private boolean mBrightChoice; private OnClickListener mSingleChoiceListener = new OnClickListener() { @Override @@ -56,11 +58,14 @@ protected void initView() { mVolumeChoice = mPreference.getBoolean(PreferenceMaster.PREF_VOLUME, false); mNightChoice = mPreference.getBoolean(PreferenceMaster.PREF_NIGHT, false); mReverseChoice = mPreference.getBoolean(PreferenceMaster.PREF_REVERSE, false); + mBrightChoice = mPreference.getBoolean(PreferenceMaster.PREF_BRIGHT, false); mHomeSummary.setText(getResources().getStringArray(R.array.home_items)[mHomeChoice]); mModeSummary.setText(getResources().getStringArray(R.array.mode_items)[mModeChoice]); mVolumeBox.setChecked(mVolumeChoice); mNightBox.setChecked(mNightChoice); mReverseBox.setChecked(mReverseChoice); + mSplitBox.setChecked(mSplitChoice); + mBrightBox.setChecked(mBrightChoice); } @OnClick(R.id.settings_other_night_btn) void onNightBtnClick() { @@ -88,6 +93,12 @@ protected void initView() { mPreference.putBoolean(PreferenceMaster.PREF_REVERSE, mReverseChoice); } + @OnClick(R.id.settings_reader_bright_btn) void onBrightClick() { + mBrightChoice = !mBrightChoice; + mBrightBox.setChecked(mBrightChoice); + mPreference.putBoolean(PreferenceMaster.PREF_BRIGHT, mBrightChoice); + } + @OnClick(R.id.settings_backup_restore_btn) void onRestoreBtnClick() { final String[] array = mPresenter.getFiles(); if (array == null) { diff --git a/app/src/main/java/com/hiroshi/cimoc/utils/ControllerBuilderFactory.java b/app/src/main/java/com/hiroshi/cimoc/utils/ControllerBuilderFactory.java index dc8c4835..cc0b3c4c 100644 --- a/app/src/main/java/com/hiroshi/cimoc/utils/ControllerBuilderFactory.java +++ b/app/src/main/java/com/hiroshi/cimoc/utils/ControllerBuilderFactory.java @@ -25,17 +25,21 @@ public class ControllerBuilderFactory { private static SparseArray builderArray = new SparseArray<>(); - public static PipelineDraweeControllerBuilder getControllerBuilder(int source, Context context) { - if (builderArray.get(source) == null) { - ImagePipelineFactory factory; - if (source == SourceManager.SOURCE_EXHENTAI) { - factory = buildFactory(context.getApplicationContext(), source, "igneous=583e748d60dc007822213a471d8e71dcba801b6a55cd0ffe04953e8adb63f294d4b60f303d9182b4276281ac883cec4c48a669db0b6c4914da78073945f49b12583e748d60dc007822213a471d8e71dcba801b6a55cd0ffe04953e8adb63f294d4b60f303d9182b4276281ac883cec4c48a669db0b6c4914da78073945f49b12"); - } else { - factory = buildFactory(context.getApplicationContext(), source, null); - } - builderArray.put(source, new PipelineDraweeControllerBuilderSupplier(context.getApplicationContext(), factory).get()); + public static PipelineDraweeControllerBuilder getCoverControllerBuilder(int source, Context context) { + PipelineDraweeControllerBuilder builder = builderArray.get(source); + if (builder == null) { + String cookie = source == SourceManager.SOURCE_EXHENTAI ? "igneous=583e748d60dc007822213a471d8e71dcba801b6a55cd0ffe04953e8adb63f294d4b60f303d9182b4276281ac883cec4c48a669db0b6c4914da78073945f49b12583e748d60dc007822213a471d8e71dcba801b6a55cd0ffe04953e8adb63f294d4b60f303d9182b4276281ac883cec4c48a669db0b6c4914da78073945f49b12" : null; + ImagePipelineFactory factory = buildFactory(context.getApplicationContext(), source, cookie); + builder = new PipelineDraweeControllerBuilderSupplier(context.getApplicationContext(), factory).get(); + builderArray.put(source, builder); } - return builderArray.get(source); + return builder; + } + + public static PipelineDraweeControllerBuilder getControllerBuilder(int source, Context context) { + String cookie = source == SourceManager.SOURCE_EXHENTAI ? "igneous=583e748d60dc007822213a471d8e71dcba801b6a55cd0ffe04953e8adb63f294d4b60f303d9182b4276281ac883cec4c48a669db0b6c4914da78073945f49b12583e748d60dc007822213a471d8e71dcba801b6a55cd0ffe04953e8adb63f294d4b60f303d9182b4276281ac883cec4c48a669db0b6c4914da78073945f49b12" : null; + ImagePipelineFactory factory = buildFactory(context.getApplicationContext(), source, cookie); + return new PipelineDraweeControllerBuilderSupplier(context.getApplicationContext(), factory).get(); } private static ImagePipelineFactory buildFactory(Context context, final int source, final String cookie) { diff --git a/app/src/main/res/layout/activity_page_reader.xml b/app/src/main/res/layout/activity_page_reader.xml index e63a7ff5..dd2060f0 100644 --- a/app/src/main/res/layout/activity_page_reader.xml +++ b/app/src/main/res/layout/activity_page_reader.xml @@ -4,44 +4,13 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/black"> - - + - - - - - + - + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_stream_reader.xml b/app/src/main/res/layout/activity_stream_reader.xml index d8ba4440..aa84bf10 100644 --- a/app/src/main/res/layout/activity_stream_reader.xml +++ b/app/src/main/res/layout/activity_stream_reader.xml @@ -3,44 +3,13 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/black"> - + - - - - - + - + \ No newline at end of file diff --git a/app/src/main/res/layout/custom_reader_info.xml b/app/src/main/res/layout/custom_reader_info.xml new file mode 100644 index 00000000..20cda3ee --- /dev/null +++ b/app/src/main/res/layout/custom_reader_info.xml @@ -0,0 +1,44 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/custom_loading.xml b/app/src/main/res/layout/custom_reader_loading.xml similarity index 100% rename from app/src/main/res/layout/custom_loading.xml rename to app/src/main/res/layout/custom_reader_loading.xml diff --git a/app/src/main/res/layout/custom_mask.xml b/app/src/main/res/layout/custom_reader_mask.xml similarity index 100% rename from app/src/main/res/layout/custom_mask.xml rename to app/src/main/res/layout/custom_reader_mask.xml diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml index 74331e90..4ea08e94 100644 --- a/app/src/main/res/layout/fragment_settings.xml +++ b/app/src/main/res/layout/fragment_settings.xml @@ -201,6 +201,38 @@ android:textSize="14sp" android:text="@string/settings_reader_split_summary"/> + + + + + 备份设置
备份 备份到本地文件 - 备份成功 数量为 + 备份成功 数量为 备份失败 没有找到备份文件 恢复 从本地文件中恢复 - 恢复成功 数量为 + 恢复成功 数量为 阅读设置 阅读模式 音量键翻页 @@ -56,6 +56,8 @@ 默认从左往右 自动切割分页 仅限卷纸模式 + 保持屏幕常亮 + 阅读状态屏幕常亮 其他设置 夜间模式 全局夜间模式 From 145072f964b516eed5b78ea7e5893c6bfe86b126 Mon Sep 17 00:00:00 2001 From: hiroshi Date: Tue, 16 Aug 2016 20:54:54 +0800 Subject: [PATCH 011/521] =?UTF-8?q?=E6=9B=B4=E6=96=B0README.md=20=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3=E5=90=84=E7=A7=8D=E5=B0=8F=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/gradle.xml | 2 +- README.md | 17 +++++++------ app/proguard-rules.pro | 4 ++- .../cimoc/core/manager/ComicManager.java | 7 ------ .../hiroshi/cimoc/core/source/EHentai.java | 3 ++- .../hiroshi/cimoc/core/source/ExHentai.java | 3 ++- .../cimoc/presenter/DetailPresenter.java | 3 +++ .../cimoc/presenter/ReaderPresenter.java | 10 +------- .../cimoc/ui/activity/ResultActivity.java | 23 +++++++++++------- .../ui/activity/StreamReaderActivity.java | 18 ++++---------- .../cimoc/ui/adapter/ChapterAdapter.java | 2 +- .../cimoc/ui/adapter/ComicAdapter.java | 8 ++++-- .../cimoc/ui/adapter/ResultAdapter.java | 8 ++++-- .../cimoc/ui/fragment/FavoriteFragment.java | 5 ++-- .../cimoc/ui/fragment/HistoryFragment.java | 1 + .../cimoc/ui/fragment/SourceFragment.java | 1 + .../com/hiroshi/cimoc/utils/BackupUtils.java | 2 -- .../cimoc/utils/ControllerBuilderFactory.java | 21 ++++++++-------- .../java/com/hiroshi/cimoc/utils/ExLog.java | 18 -------------- app/src/main/res/values/strings.xml | 1 + build.gradle | 2 +- gradle.properties | 17 ++++++------- gradle/wrapper/gradle-wrapper.properties | 4 +-- screenshot/01.png | Bin 266390 -> 238421 bytes screenshot/02.png | Bin 368889 -> 369929 bytes screenshot/03.png | Bin 748431 -> 794457 bytes screenshot/04.png | Bin 280344 -> 284349 bytes screenshot/05.png | Bin 859931 -> 817946 bytes screenshot/06.png | Bin 0 -> 223900 bytes screenshot/icon.png | Bin 5730 -> 1275 bytes 30 files changed, 81 insertions(+), 99 deletions(-) delete mode 100644 app/src/main/java/com/hiroshi/cimoc/utils/ExLog.java create mode 100644 screenshot/06.png diff --git a/.idea/gradle.xml b/.idea/gradle.xml index d52450e7..706e7504 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -5,7 +5,7 @@