Add GalleryProvider

This commit is contained in:
seven332 committed 2016-02-14 16:51:56 +08:00
1 parent 091ef383eb
commit 7ad8a3afd1
19 files changed
+1045 -292

No files matched your search

@@ -60,7 +60,6 @@ public class EhApplication extends SceneApplication {
public void onCreate() {
super.onCreate();
GetText.initialize(this);
CookieDB.initialize(this);
StatusCodeException.initialize(this);
Settings.initialize(this);
@@ -1,41 +0,0 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer;
import android.content.Context;
import android.content.res.Resources;
import android.support.annotation.NonNull;
import android.support.annotation.StringRes;
public class GetText {
private static Resources sResources;
public static void initialize(Context context) {
sResources = context.getApplicationContext().getResources();
}
@NonNull
public static String getString(@StringRes int id) {
return sResources.getString(id);
}
@NonNull
public static String getString(@StringRes int id, Object... formatArgs) {
return sResources.getString(id, formatArgs);
}
}
@@ -0,0 +1,145 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.gallery;
import android.os.Process;
import android.util.Log;
import com.hippo.image.Image;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.io.InputStream;
import java.util.Stack;
public class DirGalleryProvider extends GalleryProvider {
private static final String TAG = DirGalleryProvider.class.getSimpleName();
private File mDir;
private String[] mFiles;
private final Stack<Integer> mRequests = new Stack<>();
private boolean mRun = true;
public DirGalleryProvider(File dir) {
mDir = dir;
mFiles = mDir.list(new ImageFilter());
}
@Override
public void start() {
mRun = true;
new Decoder().start();
}
@Override
public void stop() {
mRun = false;
synchronized (mRequests) {
mRequests.notify();
}
}
@Override
public int size() {
return mFiles != null ? mFiles.length : 0;
}
@Override
@Result
public int request(int index) {
if (index < 0 || index >= size()) {
return RESULT_ERROR;
} else {
synchronized (mRequests) {
mRequests.add(index);
mRequests.notify();
}
return RESULT_WAIT;
}
}
private static final String[] ENDS = {
".jpg", // Joint Photographic Experts Group
".jpeg",
".png", // Portable Network Graphics
".gif", // Graphics Interchange Format
};
private static class ImageFilter implements FilenameFilter {
private static boolean endsWith(String str, String[] ends) {
if (str == null) {
return false;
}
for (int i = 0, n = ends.length; i < n; i++) {
if (str.endsWith(ends[i])) {
return true;
}
}
return false;
}
@Override
public boolean accept(File dir, String filename) {
return endsWith(filename.toLowerCase(), ENDS);
}
}
private class Decoder extends Thread {
@Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
while (mRun) {
int index;
synchronized (mRequests) {
if (mRequests.isEmpty()) {
try {
mRequests.wait();
} catch (InterruptedException e) {
// Ignore
}
continue;
}
index = mRequests.pop();
}
try {
InputStream is = new FileInputStream(new File(mDir, mFiles[index]));
Image image = Image.decode(is, false);
if (image != null) {
notifyPageSucceed(index, image);
} else {
notifyPageFailed(index, new Exception("Decode error"));
}
} catch (FileNotFoundException e) {
notifyPageFailed(index, e);
}
}
Log.i(TAG, "ImageDecoder end");
}
}
}
@@ -0,0 +1,148 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.gallery;
import android.os.Handler;
import android.support.annotation.IntDef;
import com.hippo.image.Image;
import com.hippo.yorozuya.Pool;
import com.hippo.yorozuya.SimpleHandler;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
public abstract class GalleryProvider {
@IntDef({RESULT_FAILED, RESULT_WAIT, RESULT_ERROR})
@Retention(RetentionPolicy.SOURCE)
public @interface Result {}
public static final int RESULT_FAILED = 0;
public static final int RESULT_WAIT = 1;
public static final int RESULT_ERROR = 2;
public static final int SIZE_WAIT = -1;
private List<GalleryProviderListener> mGalleryProviderListeners = new ArrayList<>(2);
private Pool<NotifyTask> mNotifyTaskPool = new Pool<>(5);
private Handler mHandler = SimpleHandler.getInstance();
public abstract void start();
public abstract void stop();
/**
* @return {@link #SIZE_WAIT} for wait, 0 for empty
*/
public abstract int size();
@Result
public abstract int request(int index);
public void addGalleryProviderListener(GalleryProviderListener listener) {
mGalleryProviderListeners.add(listener);
}
public void removeGalleryProviderListener(GalleryProviderListener listener) {
mGalleryProviderListeners.remove(listener);
}
public void notifyPagePercent(int index, float percent) {
notifyPage(NotifyTask.TYPE_PERCENT, index, percent, null, null);
}
public void notifyPageSucceed(int index, Image image) {
notifyPage(NotifyTask.TYPE_SUCCEED, index, 0.0f, image, null);
}
public void notifyPageFailed(int index, Exception e) {
notifyPage(NotifyTask.TYPE_FAILED, index, 0.0f, null, e);
}
private void notifyPage(@NotifyTask.Type int type, int index, float percent, Image image, Exception exception) {
NotifyTask task = mNotifyTaskPool.pop();
if (task == null) {
task = new NotifyTask(mGalleryProviderListeners, mNotifyTaskPool);
}
task.setData(type, index, percent, image, exception);
mHandler.post(task);
}
private static class NotifyTask implements Runnable {
@IntDef({TYPE_PERCENT, TYPE_SUCCEED, TYPE_FAILED})
@Retention(RetentionPolicy.SOURCE)
public @interface Type {}
public static final int TYPE_PERCENT = 0;
public static final int TYPE_SUCCEED = 1;
public static final int TYPE_FAILED = 2;
private List<GalleryProviderListener> mGalleryProviderListeners;
private Pool<NotifyTask> mPool;
@Type
private int mType;
private int mIndex;
private float mPercent;
private Image mImage;
private Exception mException;
public NotifyTask(List<GalleryProviderListener> galleryProviderListeners, Pool<NotifyTask> pool) {
mGalleryProviderListeners = galleryProviderListeners;
mPool = pool;
}
public void setData(@Type int type, int index, float percent, Image image, Exception exception) {
mType = type;
mIndex = index;
mPercent = percent;
mImage = image;
mException = exception;
}
@Override
public void run() {
switch (mType) {
case TYPE_PERCENT:
for (int i = 0, n = mGalleryProviderListeners.size(); i < n; i++) {
mGalleryProviderListeners.get(i).onPagePercent(mIndex, mPercent);
}
break;
case TYPE_SUCCEED:
for (int i = 0, n = mGalleryProviderListeners.size(); i < n; i++) {
mGalleryProviderListeners.get(i).onPageSucceed(mIndex, mImage);
}
break;
case TYPE_FAILED:
for (int i = 0, n = mGalleryProviderListeners.size(); i < n; i++) {
mGalleryProviderListeners.get(i).onPageFailed(mIndex, mException);
}
break;
}
// Clean data
mImage = null;
mException = null;
// Push back
mPool.push(this);
}
}
}
@@ -0,0 +1,28 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.gallery;
import com.hippo.image.Image;
public interface GalleryProviderListener {
void onPagePercent(int index, float percent);
void onPageSucceed(int index, Image image);
void onPageFailed(int index, Exception e);
}
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.hippo.ehviewer.ui.gl;
package com.hippo.ehviewer.gallery.gl;
import android.view.MotionEvent;
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.hippo.ehviewer.ui.gl;
package com.hippo.ehviewer.gallery.gl;
import android.content.Context;
import android.hardware.SensorManager;
@@ -0,0 +1,152 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.gallery.gl;
import com.hippo.gl.glrenderer.BasicTexture;
import com.hippo.gl.glrenderer.ImageTexture;
import com.hippo.gl.glrenderer.MovableTextTexture;
import com.hippo.gl.glrenderer.Texture;
import com.hippo.gl.view.Gravity;
import com.hippo.gl.widget.GLFrameLayout;
import com.hippo.gl.widget.GLLinearLayout;
import com.hippo.gl.widget.GLMovableTextView;
import com.hippo.gl.widget.GLProgressView;
import com.hippo.gl.widget.GLTextureView;
import com.hippo.image.Image;
public class GalleryPageView extends GLFrameLayout {
public static final float PROGRESS_GONE = -1.0f;
public static final float PROGRESS_INDETERMINATE = -2.0f;
private ImageView mImage;
private GLLinearLayout mInfo;
private GLMovableTextView mPage;
private GLTextureView mError;
private GLProgressView mProgress;
public GalleryPageView(MovableTextTexture pageTextTexture,
int progressColor, int progressSize) {
// Add image
mImage = new ImageView();
GravityLayoutParams glp = new GravityLayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
addComponent(mImage, glp);
// Add other panel
mInfo = new GLLinearLayout();
mInfo.setOrientation(GLLinearLayout.VERTICAL);
glp = new GravityLayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
glp.gravity = Gravity.CENTER;
addComponent(mInfo, glp);
// Add page
mPage = new GLMovableTextView();
mPage.setTextTexture(pageTextTexture);
GLLinearLayout.LayoutParams lp = new GLLinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
lp.gravity = Gravity.CENTER_HORIZONTAL;
mInfo.addComponent(mPage, lp);
// Add error
mError = new GLTextureView();
lp = new GLLinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
lp.gravity = Gravity.CENTER_HORIZONTAL;
mInfo.addComponent(mError, lp);
// Add progress
mProgress = new GLProgressView();
mProgress.setBgColor(GalleryView.BACKGROUND_COLOR);
mProgress.setColor(progressColor);
mProgress.setMinimumWidth(progressSize);
mProgress.setMinimumHeight(progressSize);
lp = new GLLinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
lp.gravity = Gravity.CENTER_HORIZONTAL;
mInfo.addComponent(mProgress, lp);
}
public void showImage() {
mImage.setVisibility(VISIBLE);
mInfo.setVisibility(GONE);
}
public void showInfo() {
mImage.setVisibility(GONE);
mInfo.setVisibility(VISIBLE);
}
private void unbindImage() {
Texture texture = mImage.getTexture();
if (texture != null) {
mImage.setTexture(null);
if (texture instanceof ImageTexture) {
((ImageTexture) texture).recycle();
}
}
}
public void setImage(Image image) {
unbindImage();
if (image != null) {
mImage.setTexture(new ImageTexture(image));
}
}
public void setPage(int page) {
mPage.setText(Integer.toString(page));
}
public void setProgress(float progress) {
if (progress == PROGRESS_GONE) {
mProgress.setVisibility(GONE);
} else if (progress == PROGRESS_INDETERMINATE) {
mProgress.setVisibility(VISIBLE);
mProgress.setIndeterminate(true);
} else {
mProgress.setVisibility(VISIBLE);
mProgress.setIndeterminate(false);
mProgress.setProgress(progress);
}
}
private void unbindError() {
Texture texture = mError.getTexture();
if (texture != null) {
mError.setTexture(null);
if (texture instanceof BasicTexture) {
((BasicTexture) texture).recycle();
}
}
}
public void setError(String error, GalleryView galleryView) {
unbindError();
if (error == null) {
mError.setVisibility(GONE);
} else {
mError.setVisibility(VISIBLE);
galleryView.bindErrorView(mError, error);
}
}
public ImageView getImageView() {
return mImage;
}
}
@@ -14,26 +14,30 @@
* limitations under the License.
*/
package com.hippo.ehviewer.ui.gl;
package com.hippo.ehviewer.gallery.gl;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Rect;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.MotionEvent;
import android.view.animation.Interpolator;
import android.view.animation.OvershootInterpolator;
import com.hippo.ehviewer.R;
import com.hippo.gl.annotation.RenderThread;
import com.hippo.gl.glrenderer.BasicTexture;
import com.hippo.gl.glrenderer.GLCanvas;
import com.hippo.gl.glrenderer.MovableTextTexture;
import com.hippo.gl.glrenderer.StringTexture;
import com.hippo.gl.glrenderer.Texture;
import com.hippo.gl.util.GalleryUtils;
import com.hippo.gl.view.AnimationTime;
import com.hippo.gl.view.GLRoot;
import com.hippo.gl.view.GLView;
import com.hippo.gl.widget.GLEdgeView;
import com.hippo.gl.widget.GLProgressView;
import com.hippo.gl.widget.GLTextureView;
import com.hippo.yorozuya.LayoutUtils;
import com.hippo.yorozuya.ResourcesUtils;
@@ -43,10 +47,6 @@ import java.util.Stack;
public class GalleryView extends GLView implements GestureRecognizer.Listener {
@IntDef({PAGE_STATE_UNKNOWN_SEEN, PAGE_STATE_SEEN, PAGE_STATE_UNSEEN})
@Retention(RetentionPolicy.SOURCE)
private @interface PageState {}
@IntDef({SCALE_ORIGIN, SCALE_FIT_WIDTH, SCALE_FIT_HEIGHT, SCALE_FIT, SCALE_FIXED})
@Retention(RetentionPolicy.SOURCE)
public @interface Scale {}
@@ -60,17 +60,11 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
@Retention(RetentionPolicy.SOURCE)
private @interface LayoutMode {}
private static final int NO_POSITION = -1;
private static final int MAX_SETTLE_DURATION = 600; // ms
private static final int BACKGROUND_COLOR = 0xff212121;
public static final int BACKGROUND_COLOR = 0xff212121;
private static final int INTERVAL_IN_DP = 24;
private static final int PROGRESS_SIZE_IN_DP = 48;
private static final int PAGE_MIN_HEIGHT_IN_DP = 256;
private static final int PAGE_STATE_UNKNOWN_SEEN = 0;
private static final int PAGE_STATE_SEEN = 1;
private static final int PAGE_STATE_UNSEEN = 2;
public static final int SCALE_ORIGIN = 0;
public static final int SCALE_FIT_WIDTH = 1;
public static final int SCALE_FIT_HEIGHT = 2;
@@ -87,27 +81,32 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
public static final int LAYOUT_MODE_RIGHT_TO_LEFT = 1;
public static final int LAYOUT_MODE_TOP_TO_BOTTOM = 2;
private static final Interpolator SMOOTH_SCALER_INTERPOLATOR = new OvershootInterpolator(0.7f);
private static final float[] LEFT_AREA = {0.0f, 0.0f, 1.0f / 3.0f, 1f};
private static final float[] RIGHT_AREA = {2.0f / 3.0f, 0.0f, 1.0f, 1f};
private static final float[] CENTER_AREA = {1.0f / 3.0f, 2.0f / 5.0f, 2.0f / 3.0f, 3.0f / 5.0f};
private Context mContext;
private MovableTextTexture mPageTextTexture;
private GestureRecognizer mGestureRecognizer;
private PageIterator mIterator;
private LayoutManager mPagerLayoutManager;
private LayoutManager mScrollLayoutManager;
private PagerLayoutManager mPagerLayoutManager;
private ScrollLayoutManager mScrollLayoutManager;
private LayoutManager mLayoutManager;
private Recycler mRecycler;
private GLEdgeView mEdgeView;
private GLProgressView mProgressCache;
private GLTextureView mErrorViewCache;
private int mProgressColor;
private int mProgressSize;
private float mErrorSize;
private int mErrorColor;
private int mPageMinHeight;
private int mInterval;
private boolean mEnableRequestLayout = true;
private boolean mEnableRequestFill = true;
private boolean mScale = false;
private boolean mScroll = false;
@@ -120,8 +119,6 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
@LayoutMode
private int mLayoutMode = LAYOUT_MODE_RIGHT_TO_LEFT;
@LayoutMode
private int mLastLayoutMode = mLayoutMode;
@Scale
private int mScaleMode = SCALE_FIT;
@@ -132,64 +129,131 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
private ActionListener mListener;
public GalleryView(Context context, PageIterator iterator, ActionListener listener) {
public GalleryView(Context context, PageIterator iterator, MovableTextTexture pageTextTexture,
ActionListener listener, @LayoutMode int layoutMode) {
mContext = context;
mIterator = iterator;
mPageTextTexture = pageTextTexture;
mListener = listener;
mEdgeView = new GLEdgeView(context);
mGestureRecognizer = new GestureRecognizer(context, this);
mRecycler = new Recycler();
mProgressColor = ResourcesUtils.getAttrColor(context, R.attr.colorPrimary);
mPageMinHeight = LayoutUtils.dp2pix(context, PAGE_MIN_HEIGHT_IN_DP);
iterator.setGalleryView(this);
int interval = LayoutUtils.dp2pix(context, INTERVAL_IN_DP);
int progressSize = LayoutUtils.dp2pix(context, PROGRESS_SIZE_IN_DP);
mPagerLayoutManager = new PagerLayoutManager(context, this, interval, progressSize);
mScrollLayoutManager = new ScrollLayoutManager(context, this, interval, progressSize);
mScrollLayoutManager.onAttach(iterator);
mLayoutManager = mScrollLayoutManager;
mLayoutMode = layoutMode;
mProgressColor = ResourcesUtils.getAttrColor(context, R.attr.colorPrimary);
mProgressSize = LayoutUtils.dp2pix(context, PROGRESS_SIZE_IN_DP);
mErrorSize = context.getResources().getDimension(R.dimen.text_medium);
mErrorColor = Color.RED;
mPageMinHeight = LayoutUtils.dp2pix(context, PAGE_MIN_HEIGHT_IN_DP);
mInterval = LayoutUtils.dp2pix(context, INTERVAL_IN_DP);
setBackgroundColor(BACKGROUND_COLOR);
}
private void ensurePagerLayoutManager() {
if (mPagerLayoutManager == null) {
mPagerLayoutManager = new PagerLayoutManager(mContext, this, mInterval);
}
}
private void ensureScrollLayoutManager() {
if (mScrollLayoutManager == null) {
mScrollLayoutManager = new ScrollLayoutManager(mContext, this, mInterval);
}
}
@Override
public void onAttachToRoot(GLRoot root) {
super.onAttachToRoot(root);
mEdgeView.onAttachToRoot(root);
switch (mLayoutMode) {
case LAYOUT_MODE_LEFT_TO_RIGHT:
ensurePagerLayoutManager();
mPagerLayoutManager.setMode(PagerLayoutManager.MODE_LEFT_TO_RIGHT);
mPagerLayoutManager.onAttach(mIterator);
mIterator = null;
mLayoutManager = mPagerLayoutManager;
break;
case LAYOUT_MODE_RIGHT_TO_LEFT:
ensurePagerLayoutManager();
mPagerLayoutManager.setMode(PagerLayoutManager.MODE_RIGHT_TO_LEFT);
mPagerLayoutManager.onAttach(mIterator);
mIterator = null;
mLayoutManager = mPagerLayoutManager;
break;
case LAYOUT_MODE_TOP_TO_BOTTOM:
ensureScrollLayoutManager();
mScrollLayoutManager.onAttach(mIterator);
mIterator = null;
mLayoutManager = mScrollLayoutManager;
break;
}
}
@Override
public void onDetachFromRoot() {
super.onDetachFromRoot();
mEdgeView.onDetachFromRoot();
mIterator = mLayoutManager.onDetach();
mLayoutManager = null;
}
/*
public void setMode(Mode mode) {
if (mMode != mode) {
Mode oldMode = mMode;
mMode = mode;
resetPageMoving();
superRequestLayout();
public void setLayoutMode(@LayoutMode int layoutMode) {
if (mLayoutMode == layoutMode) {
return;
}
mLayoutMode = layoutMode;
mListener.onSetMode(mode);
if (oldMode == Mode.NONE) {
mFirstShownIndex = MathUtils.clamp(mFirstShownIndex, 0, mAdapter.getPages() - 1);
mListener.onScrollToPage(mFirstShownIndex, true);
}
if (mLayoutManager == null) {
return;
}
switch (mLayoutMode) {
case LAYOUT_MODE_LEFT_TO_RIGHT:
if (mLayoutManager == mPagerLayoutManager) {
// mPagerLayoutManager already attached, just change mode
mPagerLayoutManager.setMode(PagerLayoutManager.MODE_LEFT_TO_RIGHT);
} else {
ensurePagerLayoutManager();
mPagerLayoutManager.setMode(PagerLayoutManager.MODE_LEFT_TO_RIGHT);
mPagerLayoutManager.onAttach(mLayoutManager.onDetach());
mLayoutManager = mPagerLayoutManager;
}
break;
case LAYOUT_MODE_RIGHT_TO_LEFT:
if (mLayoutManager == mPagerLayoutManager) {
// mPagerLayoutManager already attached, just change mode
mPagerLayoutManager.setMode(PagerLayoutManager.MODE_RIGHT_TO_LEFT);
} else {
ensurePagerLayoutManager();
mPagerLayoutManager.setMode(PagerLayoutManager.MODE_RIGHT_TO_LEFT);
mPagerLayoutManager.onAttach(mLayoutManager.onDetach());
mLayoutManager = mPagerLayoutManager;
}
break;
case LAYOUT_MODE_TOP_TO_BOTTOM:
ensureScrollLayoutManager();
mScrollLayoutManager.onAttach(mLayoutManager.onDetach());
mLayoutManager = mScrollLayoutManager;
break;
}
}
*/
public void superRequestLayout() {
super.requestLayout();
@Override
public void requestLayout() {
// Do not need requestLayout, because the size will not change
requestFill();
}
public void requestFill() {
mRequestFill = true;
invalidate();
if (mEnableRequestFill) {
mRequestFill = true;
invalidate();
}
}
@Override
@@ -220,11 +284,12 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
return false;
}
mLayoutManager.onDoubleTapConfirmed(x, y);
if (mLayoutManager != null) {
mLayoutManager.onDoubleTapConfirmed(x, y);
}
return true;
}
GLEdgeView getEdgeView() {
return mEdgeView;
}
@@ -242,14 +307,18 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
}
mScroll = true;
mLayoutManager.onScroll(dx, dy, totalX, totalY, x, y);
if (mLayoutManager != null) {
mLayoutManager.onScroll(dx, dy, totalX, totalY, x, y);
}
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
mLayoutManager.onFling(e1, e2, velocityX, velocityY);
if (mLayoutManager != null) {
mLayoutManager.onFling(e1, e2, velocityX, velocityY);
}
return true;
}
@@ -260,12 +329,14 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
@Override
public boolean onScale(float focusX, float focusY, float scale) {
if (mScroll || !mLayoutManager.canScale()) {
if (mScroll || (mLayoutManager != null && !mLayoutManager.canScale())) {
return false;
}
mScale = true;
mLayoutManager.onScale(focusX, focusY, scale);
if (mLayoutManager != null) {
mLayoutManager.onScale(focusX, focusY, scale);
}
return true;
}
@@ -280,18 +351,22 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
mScale = false;
mScroll = false;
mFirstScroll = true;
mLayoutManager.onDown();
if (mLayoutManager != null) {
mLayoutManager.onDown();
}
}
@Override
public void onUp() {
mTouched = false;
mLayoutManager.onUp();
if (mLayoutManager != null) {
mLayoutManager.onUp();
}
}
@Override
public void onPointerDown(float x, float y) {
if (!mScroll && mLayoutManager.canScale()) {
if (!mScroll && (mLayoutManager != null && mLayoutManager.canScale())) {
mScale = true;
}
}
@@ -301,13 +376,6 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
}
@Override
public void requestLayout() {
if (mEnableRequestLayout) {
super.requestLayout();
}
}
@Override
protected void onLayout(boolean changeSize, int left, int top, int right, int bottom) {
@@ -333,16 +401,17 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
GalleryUtils.assertInRenderThread();
// Disable request layout
mEnableRequestLayout = false;
mLayoutManager.onFill();
mEnableRequestLayout = true;
mEnableRequestFill = false;
if (mLayoutManager != null) {
mLayoutManager.onFill();
}
mEnableRequestFill = true;
}
@Override
public void render(GLCanvas canvas) {
long time = AnimationTime.get();
boolean invalidate = mLayoutManager.onUpdateAnimation(time);
if (invalidate) {
if (mLayoutManager != null && mLayoutManager.onUpdateAnimation(time)) {
invalidate();
}
@@ -356,10 +425,18 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
mEdgeView.render(canvas);
}
public GalleryPageView findPageById(int id) {
if (mLayoutManager != null) {
return mLayoutManager.findPageById(id);
} else {
return null;
}
}
public GalleryPageView obtainPage() {
GalleryPageView page = mRecycler.obtain();
if (page == null) {
page = new GalleryPageView(mContext);
page = new GalleryPageView(mPageTextTexture, mProgressColor, mProgressSize);
page.setMinimumHeight(mPageMinHeight);
}
return page;
@@ -382,6 +459,8 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
progress.setColor(mProgressColor);
progress.setBgColor(BACKGROUND_COLOR);
progress.setIndeterminate(true);
progress.setMinimumWidth(mProgressSize);
progress.setMinimumHeight(mProgressSize);
}
return progress;
}
@@ -393,25 +472,88 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
mProgressCache = progress;
}
public interface PageIterator {
public GLTextureView obtainErrorView() {
GLTextureView errorView;
if (mErrorViewCache != null) {
errorView = mErrorViewCache;
mErrorViewCache = null;
} else {
errorView = new GLTextureView();
}
return errorView;
}
void mark();
public void unbindErrorView(GLTextureView errorView) {
Texture texture = errorView.getTexture();
if (texture != null) {
errorView.setTexture(null);
if (texture instanceof BasicTexture) {
((BasicTexture) texture).recycle();
}
}
}
void reset();
public void bindErrorView(GLTextureView errorView, String error) {
unbindErrorView(errorView);
boolean hasNext();
Texture texture = StringTexture.newInstance(error, mErrorSize, mErrorColor);
errorView.setTexture(texture);
}
boolean hasPrevious();
public void releaseErrorView(GLTextureView errorView) {
unbindErrorView(errorView);
mErrorViewCache = errorView;
}
boolean isValid();
public void onDataChanged() {
if (mLayoutManager != null){
mLayoutManager.onDataChanged();
}
}
void next();
public static abstract class PageIterator {
void previous();
protected GalleryView mGalleryView;
void bind(GalleryPageView view);
private void setGalleryView(@NonNull GalleryView galleryView) {
mGalleryView = galleryView;
}
void unbind(GalleryPageView view);
public abstract void mark();
public abstract void reset();
public abstract boolean isBusy();
/**
* Null for no error
*/
public abstract String isError();
public abstract boolean hasNext();
public abstract boolean hasPrevious();
public abstract void next();
public abstract void previous();
public void bind(GalleryPageView view) {
view.setId(onBind(view));
}
public void unbind(GalleryPageView view) {
onUnbind(view);
view.setId(NO_ID);
}
public abstract int onBind(GalleryPageView view);
public abstract void onUnbind(GalleryPageView view);
public void notifyDataChanged() {
mGalleryView.onDataChanged();
}
}
public static abstract class LayoutManager {
@@ -443,6 +585,21 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
public abstract void onScale(float focusX, float focusY, float scale);
public abstract boolean onUpdateAnimation(long time);
public abstract void onDataChanged();
public abstract GalleryPageView findPageById(int id);
protected void placeCenter(GLView view) {
int spec = GLView.MeasureSpec.makeMeasureSpec(GLView.LayoutParams.WRAP_CONTENT,
GLView.LayoutParams.WRAP_CONTENT);
view.measure(spec, spec);
int viewWidth = view.getMeasuredWidth();
int viewHeight = view.getMeasuredHeight();
int viewLeft = mGalleryView.getWidth() / 2 - viewWidth / 2;
int viewTop = mGalleryView.getHeight() / 2 - viewHeight / 2;
view.layout(viewLeft, viewTop, viewLeft + viewWidth, viewTop + viewHeight);
}
}
private static class Recycler {
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.hippo.ehviewer.ui.gl;
package com.hippo.ehviewer.gallery.gl;
import android.content.Context;
import android.os.SystemClock;
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.hippo.ehviewer.ui.gl;
package com.hippo.ehviewer.gallery.gl;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -178,6 +178,10 @@ public class ImageView extends GLView {
mPositionInRootDirty = true;
}
public Texture getTexture() {
return mTexture;
}
public boolean isLoaded() {
return mTexture != null;
}
@@ -14,12 +14,11 @@
* limitations under the License.
*/
package com.hippo.ehviewer.ui.gl;
package com.hippo.ehviewer.gallery.gl;
import android.content.Context;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.util.Log;
import android.view.MotionEvent;
import android.view.animation.Interpolator;
@@ -28,6 +27,7 @@ import com.hippo.gl.anim.Animation;
import com.hippo.gl.view.GLView;
import com.hippo.gl.widget.GLEdgeView;
import com.hippo.gl.widget.GLProgressView;
import com.hippo.gl.widget.GLTextureView;
import com.hippo.yorozuya.AssertUtils;
import com.hippo.yorozuya.MathUtils;
@@ -40,8 +40,8 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
@Retention(RetentionPolicy.SOURCE)
private @interface Mode {}
private static final int MODE_LEFT_TO_RIGHT = 0;
private static final int MODE_RIGHT_TO_LEFT = 1;
public static final int MODE_LEFT_TO_RIGHT = 0;
public static final int MODE_RIGHT_TO_LEFT = 1;
private static final Interpolator SMOOTH_SCROLLER_INTERPOLATOR = new Interpolator() {
@Override
@@ -54,6 +54,8 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
private GalleryView.PageIterator mIterator;
private GLProgressView mProgress;
private String mErrorStr;
private GLTextureView mErrorView;
private GalleryPageView mPrevious;
private GalleryPageView mCurrent;
private GalleryPageView mNext;
@@ -66,7 +68,6 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
private boolean mCanScrollBetweenPages = false;
private int mInterval;
private int mProgressSpec;
private int[] mScrollRemain = new int[2];
private float[] mScaleDefault = new float[3];
@@ -76,10 +77,9 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
private SmoothScaler mSmoothScaler;
public PagerLayoutManager(Context context, @NonNull GalleryView galleryView,
int interval, int progressSize) {
int interval) {
super(galleryView);
mInterval = interval;
mProgressSpec = GLView.MeasureSpec.makeMeasureSpec(progressSize, GLView.MeasureSpec.EXACTLY);
mPageFling = new PageFling(context);
mSmoothScroller = new SmoothScroller();
@@ -111,6 +111,7 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
cancelAllAnimations();
// Remove all view
removeProgress();
removeErrorView();
removeAllPages();
// Reset parameters
resetParameters();
@@ -122,6 +123,7 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
@Override
public void onAttach(GalleryView.PageIterator iterator) {
AssertUtils.assertEquals("The PagerLayoutManager is attached", mIterator, null);
AssertUtils.assertNotEquals("The iterator is null", iterator, null);
mIterator = iterator;
// Reset parameters
resetParameters();
@@ -130,10 +132,20 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
private void removeProgress() {
if (mProgress != null) {
mGalleryView.removeComponent(mProgress);
mGalleryView.releaseProgress(mProgress);
mProgress = null;
}
}
private void removeErrorView() {
if (mErrorView != null) {
mGalleryView.removeComponent(mErrorView);
mGalleryView.releaseErrorView(mErrorView);
mErrorView = null;
mErrorStr = null;
}
}
private void removePage(@NonNull GalleryPageView page) {
mGalleryView.removeComponent(page);
mIterator.unbind(page);
@@ -165,6 +177,7 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
// Remove all view
removeProgress();
removeErrorView();
removeAllPages();
// Clear iterator
@@ -226,9 +239,30 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
int width = galleryView.getWidth();
int height = galleryView.getHeight();
String errorStr = iterator.isError();
if (!iterator.isValid()) {
// Remove all pages
if (errorStr != null) {
// Remove progress and all pages
removeProgress();
removeAllPages();
// Ensure error view
if (mErrorView == null) {
mErrorView = galleryView.obtainErrorView();
galleryView.addComponent(mErrorView);
}
// Update error string
if (!errorStr.equals(mErrorStr)) {
mErrorStr = errorStr;
galleryView.bindErrorView(mErrorView, errorStr);
}
// Place error view center
placeCenter(mErrorView);
} else if (iterator.isBusy()) {
// Remove error view and all pages
removeErrorView();
removeAllPages();
// Ensure progress
@@ -237,16 +271,12 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
galleryView.addComponent(mProgress);
}
// Measure and layout progress
mProgress.measure(mProgressSpec, mProgressSpec);
int progressWidth = mProgress.getMeasuredWidth();
int progressHeight = mProgress.getMeasuredHeight();
int progressLeft = width / 2 - progressWidth / 2;
int progressTop = height / 2 - progressHeight / 2;
mProgress.layout(progressLeft, progressTop, progressLeft + progressWidth, progressTop + progressHeight);
// Place progress center
placeCenter(mProgress);
} else {
// Remove progress
// Remove progress and error view
removeProgress();
removeErrorView();
// Ensure pages
if (mCurrent == null) {
@@ -474,9 +504,6 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
mDeltaX += dx;
mDeltaY += dy;
Log.d("TAG", "mDeltaX = " + mDeltaX);
if (mDeltaX < 0) {
edgeView.onPull(-mDeltaX, y, GLEdgeView.LEFT);
if (!edgeView.isFinished(GLEdgeView.RIGHT)) {
@@ -593,6 +620,35 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
return invalidate;
}
@Override
public void onDataChanged() {
AssertUtils.assertNotEquals("The PagerLayoutManager is not attached", mIterator, null);
// Cancel all animations
cancelAllAnimations();
// Remove all views
removeProgress();
removeErrorView();
removeAllPages();
// Reset parameters
resetParameters();
mGalleryView.requestFill();
}
@Override
public GalleryPageView findPageById(int id) {
if (mCurrent != null && mCurrent.getId() == id) {
return mCurrent;
}
if (mPrevious != null && mPrevious.getId() == id) {
return mPrevious;
}
if (mNext != null && mNext.getId() == id) {
return mNext;
}
return null;
}
class SmoothScroller extends Animation {
private int mDx;
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.hippo.ehviewer.ui.gl;
package com.hippo.ehviewer.gallery.gl;
import android.content.Context;
import android.support.annotation.NonNull;
@@ -24,6 +24,7 @@ import android.view.MotionEvent;
import com.hippo.gl.view.GLView;
import com.hippo.gl.widget.GLEdgeView;
import com.hippo.gl.widget.GLProgressView;
import com.hippo.gl.widget.GLTextureView;
import com.hippo.yorozuya.AssertUtils;
import java.util.Iterator;
@@ -38,6 +39,8 @@ public class ScrollLayoutManager extends GalleryView.LayoutManager {
private GalleryView.PageIterator mIterator;
private GLProgressView mProgress;
private String mErrorStr;
private GLTextureView mErrorView;
private LinkedList<GalleryPageView> mPages = new LinkedList<>();
private int mOffset;
@@ -50,11 +53,12 @@ public class ScrollLayoutManager extends GalleryView.LayoutManager {
private PageFling mPageFling;
public ScrollLayoutManager(Context context, @NonNull GalleryView galleryView,
int interval, int progressSize) {
int interval) {
super(galleryView);
mInterval = interval;
mProgressSpec = GLView.MeasureSpec.makeMeasureSpec(progressSize, GLView.MeasureSpec.EXACTLY);
mProgressSpec = GLView.MeasureSpec.makeMeasureSpec(GLView.LayoutParams.WRAP_CONTENT,
GLView.LayoutParams.WRAP_CONTENT);
mPageFling = new PageFling(context);
}
@@ -70,7 +74,8 @@ public class ScrollLayoutManager extends GalleryView.LayoutManager {
@Override
public void onAttach(GalleryView.PageIterator iterator) {
AssertUtils.assertEquals("The PagerLayoutManager is attached", mIterator, null);
AssertUtils.assertEquals("The ScrollLayoutManager is attached", mIterator, null);
AssertUtils.assertNotEquals("The iterator is null", iterator, null);
mIterator = iterator;
// Reset parameters
resetParameters();
@@ -79,10 +84,20 @@ public class ScrollLayoutManager extends GalleryView.LayoutManager {
private void removeProgress() {
if (mProgress != null) {
mGalleryView.removeComponent(mProgress);
mGalleryView.releaseProgress(mProgress);
mProgress = null;
}
}
private void removeErrorView() {
if (mErrorView != null) {
mGalleryView.removeComponent(mErrorView);
mGalleryView.releaseErrorView(mErrorView);
mErrorView = null;
mErrorStr = null;
}
}
private void removePage(@NonNull GalleryPageView page) {
mGalleryView.removeComponent(page);
mIterator.unbind(page);
@@ -105,6 +120,7 @@ public class ScrollLayoutManager extends GalleryView.LayoutManager {
// Remove all view
removeProgress();
removeErrorView();
removeAllPages();
// Clear iterator
@@ -122,9 +138,30 @@ public class ScrollLayoutManager extends GalleryView.LayoutManager {
int width = galleryView.getWidth();
int height = galleryView.getHeight();
String errorStr = iterator.isError();
if (!iterator.isValid()) {
// Remove all pages
if (errorStr != null) {
// Remove progress and all pages
removeProgress();
removeAllPages();
// Ensure error view
if (mErrorView == null) {
mErrorView = galleryView.obtainErrorView();
galleryView.addComponent(mErrorView);
}
// Update error string
if (!errorStr.equals(mErrorStr)) {
mErrorStr = errorStr;
galleryView.bindErrorView(mErrorView, errorStr);
}
// Place error view center
placeCenter(mErrorView);
} else if (iterator.isBusy()) {
// Remove error view and all pages
removeErrorView();
removeAllPages();
// Ensure progress
@@ -133,16 +170,12 @@ public class ScrollLayoutManager extends GalleryView.LayoutManager {
galleryView.addComponent(mProgress);
}
// Measure and layout progress
mProgress.measure(mProgressSpec, mProgressSpec);
int progressWidth = mProgress.getMeasuredWidth();
int progressHeight = mProgress.getMeasuredHeight();
int progressLeft = width / 2 - progressWidth / 2;
int progressTop = height / 2 - progressHeight / 2;
mProgress.layout(progressLeft, progressTop, progressLeft + progressWidth, progressTop + progressHeight);
// Place progress center
placeCenter(mProgress);
} else {
// Remove progress
// Remove progress and error view
removeProgress();
removeErrorView();
int minY = (int) (-height * RESERVATIONS);
@@ -498,6 +531,32 @@ public class ScrollLayoutManager extends GalleryView.LayoutManager {
return invalidate;
}
@Override
public void onDataChanged() {
AssertUtils.assertNotEquals("The PagerLayoutManager is not attached", mIterator, null);
// Cancel all animations
cancelAllAnimations();
// Remove all views
removeProgress();
removeErrorView();
removeAllPages();
// Reset parameters
resetParameters();
mGalleryView.requestFill();
}
@Override
public GalleryPageView findPageById(int id) {
for (int i = 0, n = mPages.size(); i < n; i++) {
GalleryPageView page = mPages.get(i);
if (page.getId() == id) {
return page;
}
}
return null;
}
class PageFling extends Fling {
private int mVelocityX;
@@ -16,26 +16,42 @@
package com.hippo.ehviewer.ui;
import android.graphics.Typeface;
import android.os.Bundle;
import android.os.Environment;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.util.SparseIntArray;
import android.view.KeyEvent;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.ui.gl.GalleryPageView;
import com.hippo.ehviewer.ui.gl.GalleryView;
import com.hippo.ehviewer.gallery.DirGalleryProvider;
import com.hippo.ehviewer.gallery.GalleryProvider;
import com.hippo.ehviewer.gallery.GalleryProviderListener;
import com.hippo.ehviewer.gallery.gl.GalleryPageView;
import com.hippo.ehviewer.gallery.gl.GalleryView;
import com.hippo.gl.glrenderer.ImageTexture;
import com.hippo.gl.glrenderer.MovableTextTexture;
import com.hippo.gl.view.GLRootView;
import com.hippo.gl.view.GLView;
import com.hippo.image.Image;
import com.hippo.yorozuya.IntIdGenerator;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.File;
public class GalleryActivity extends AppCompatActivity {
public class GalleryActivity extends AppCompatActivity implements GalleryProviderListener {
@Nullable
private GalleryView mGalleryView;
@Nullable
private MovableTextTexture mPageTextTexture;
@Nullable
private ImageTexture.Uploader mUploader;
@Nullable
private GalleryProvider mGalleryProvider;
@Nullable
private SparseIntArray mIndexIdMap;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
@@ -43,16 +59,41 @@ public class GalleryActivity extends AppCompatActivity {
setContentView(R.layout.activity_gallery);
GLRootView glRootView = (GLRootView) findViewById(R.id.gl_root_view);
mGalleryView = new GalleryView(this, new InvalidPageIterator(), null);
glRootView.setContentPane(mGalleryView);
mUploader = new ImageTexture.Uploader(glRootView);
mIndexIdMap = new SparseIntArray();
mGalleryProvider = new DirGalleryProvider(new File(Environment.getExternalStorageDirectory(), "nmb/image"));
mGalleryProvider.addGalleryProviderListener(this);
mGalleryProvider.start();
mPageTextTexture = MovableTextTexture.create(Typeface.DEFAULT,
getResources().getDimensionPixelSize(R.dimen.gallery_page_text),
getResources().getColor(R.color.secondary_text_dark),
new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'});
mGalleryView = new GalleryView(this, new GalleryPageIterator(),
mPageTextTexture, null, GalleryView.LAYOUT_MODE_LEFT_TO_RIGHT);
glRootView.setContentPane(mGalleryView);
}
@Override
protected void onDestroy() {
super.onDestroy();
mGalleryView = null;
mUploader = null;
if (mUploader != null) {
mUploader.clear();
mUploader = null;
}
if (mPageTextTexture != null) {
mPageTextTexture.recycle();
mPageTextTexture = null;
}
if (mGalleryProvider != null) {
mGalleryProvider.removeGalleryProviderListener(this);
mGalleryProvider.stop();
mGalleryProvider = null;
}
mIndexIdMap = null;
}
@Override
@@ -128,24 +169,61 @@ public class GalleryActivity extends AppCompatActivity {
return super.onKeyUp(keyCode, event);
}
private GalleryPageView findPageByIndex(int index) {
if (mIndexIdMap == null || mGalleryView == null) {
return null;
}
private static final int MAX_SIZE = 2;
int id = mIndexIdMap.get(index, GLView.NO_ID);
if (id == GLView.NO_ID) {
return null;
}
private class InvalidPageIterator implements GalleryView.PageIterator {
return mGalleryView.findPageById(id);
}
@Override
public void onPagePercent(int index, float percent) {
GalleryPageView page = findPageByIndex(index);
if (page != null) {
page.showInfo();
page.setImage(null);
page.setPage(index + 1);
page.setProgress(percent);
page.setError(null, null);
}
}
@Override
public void onPageSucceed(int index, Image image) {
GalleryPageView page = findPageByIndex(index);
if (page != null) {
page.showImage();
page.setImage(image);
page.setPage(index + 1);
page.setProgress(GalleryPageView.PROGRESS_GONE);
page.setError(null, null);
}
}
@Override
public void onPageFailed(int index, Exception e) {
GalleryPageView page = findPageByIndex(index);
if (page != null && mGalleryView != null) {
page.showInfo();
page.setImage(null);
page.setPage(index + 1);
page.setProgress(GalleryPageView.PROGRESS_GONE);
page.setError("Error", mGalleryView);
}
}
private class GalleryPageIterator extends GalleryView.PageIterator {
private IntIdGenerator mIdGenerator = new IntIdGenerator();
private int mIndex = 0;
private int mBackup = mIndex;
public ImageTexture mImageTexture;
public InvalidPageIterator() {
try {
mImageTexture = new ImageTexture(Image.decode(new FileInputStream("/sdcard/1.jpg"), false));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
@Override
public void mark() {
mBackup = mIndex;
@@ -156,9 +234,28 @@ public class GalleryActivity extends AppCompatActivity {
mIndex = mBackup;
}
@Override
public boolean isBusy() {
return mGalleryProvider == null ||
mGalleryProvider.size() == GalleryProvider.SIZE_WAIT;
}
@Override
public String isError() {
if (mGalleryProvider != null) {
int size = mGalleryProvider.size();
if (size == 0) {
return "Empty Gallery"; // TODO hardcode
} else if (size < 0 && size != GalleryProvider.SIZE_WAIT) {
return "Weird"; // TODO hardcode
}
}
return null;
}
@Override
public boolean hasNext() {
return mIndex < MAX_SIZE - 1;
return mGalleryProvider != null && mIndex < mGalleryProvider.size() - 1;
}
@Override
@@ -166,14 +263,9 @@ public class GalleryActivity extends AppCompatActivity {
return mIndex > 0;
}
@Override
public boolean isValid() {
return mIndex >= 0 && mIndex < MAX_SIZE;
}
@Override
public void next() {
if (mIndex >= MAX_SIZE - 1) {
if (mGalleryProvider != null && mIndex >= mGalleryProvider.size() - 1) {
throw new IndexOutOfBoundsException();
}
mIndex++;
@@ -188,14 +280,51 @@ public class GalleryActivity extends AppCompatActivity {
}
@Override
public void bind(GalleryPageView view) {
view.showImage();
view.getImageView().setTexture(mImageTexture);
public int onBind(GalleryPageView view) {
if (mGalleryProvider != null && mGalleryView != null) {
switch (mGalleryProvider.request(mIndex)) {
case GalleryProvider.RESULT_WAIT:
view.showInfo();
view.setImage(null);
view.setPage(mIndex + 1);
view.setProgress(GalleryPageView.PROGRESS_INDETERMINATE);
view.setError(null, null);
break;
case GalleryProvider.RESULT_FAILED:
view.showInfo();
view.setImage(null);
view.setPage(mIndex + 1);
view.setProgress(GalleryPageView.PROGRESS_GONE);
view.setError("Failed", mGalleryView);
break;
case GalleryProvider.RESULT_ERROR:
view.showInfo();
view.setImage(null);
view.setPage(mIndex + 1);
view.setProgress(GalleryPageView.PROGRESS_GONE);
view.setError("Error", mGalleryView);
break;
}
}
int id = mIdGenerator.nextId();
if (mIndexIdMap != null) {
mIndexIdMap.put(mIndex, id);
}
return id;
}
@Override
public void unbind(GalleryPageView view) {
view.getImageView().setTexture(null);
public void onUnbind(GalleryPageView view) {
if (mIndexIdMap != null) {
int index = mIndexIdMap.indexOfKey(view.getId());
if (index >= 0) {
mIndexIdMap.removeAt(index);
}
}
view.setImage(null);
view.setError(null, null);
}
}
}
@@ -1,89 +0,0 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.ui.gl;
import android.content.Context;
import com.hippo.gl.glrenderer.TextTexture;
import com.hippo.gl.view.Gravity;
import com.hippo.gl.widget.GLFrameLayout;
import com.hippo.gl.widget.GLLinearLayout;
import com.hippo.gl.widget.GLProgressView;
import com.hippo.gl.widget.GLTextView;
import com.hippo.gl.widget.GLTextureView;
import com.hippo.yorozuya.LayoutUtils;
public class GalleryPageView extends GLFrameLayout {
private ImageView mImage;
private GLLinearLayout mInfo;
private GLTextView mPage;
private GLTextureView mError;
private GLProgressView mProgress;
// TODO
private static TextTexture sPageTextTexture;
public GalleryPageView(Context context) {
// Add image
mImage = new ImageView();
GravityLayoutParams glp = new GravityLayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
addComponent(mImage, glp);
// Add other panel
mInfo = new GLLinearLayout();
mInfo.setOrientation(GLLinearLayout.VERTICAL);
glp = new GravityLayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
glp.gravity = Gravity.CENTER;
addComponent(mInfo, glp);
// Add page
mPage = new GLTextView();
mPage.setTextTexture(sPageTextTexture);
GLLinearLayout.LayoutParams lp = new GLLinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
lp.gravity = Gravity.CENTER_HORIZONTAL;
mInfo.addComponent(mPage, lp);
// Add error
mError = new GLTextureView();
lp = new GLLinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
lp.gravity = Gravity.CENTER_HORIZONTAL;
mInfo.addComponent(mError, lp);
// Add progress
mProgress = new GLProgressView();
mProgress.setMinimumWidth(LayoutUtils.dp2pix(context, 56)); // 56dp
mProgress.setMinimumHeight(LayoutUtils.dp2pix(context, 56)); // 56dp
lp = new GLLinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
lp.gravity = Gravity.CENTER_HORIZONTAL;
mInfo.addComponent(mProgress, lp);
}
public void showImage() {
mImage.setVisibility(VISIBLE);
mInfo.setVisibility(INVISIBLE);
}
public ImageView getImageView() {
return mImage;
}
}
@@ -536,4 +536,13 @@ public class ImageTexture implements Texture {
public boolean isReady() {
return mUploadIndex == mTiles.length;
}
public void recycle() {
for (int i = 0, n = mTiles.length; i < n; ++i) {
mTiles[i].free();
}
synchronized (mImage) {
mImage.recycle();
}
}
}
@@ -52,7 +52,7 @@ import java.util.ArrayList;
public class GLView implements TouchOwner {
private static final String TAG = "GLView";
private static final boolean DEBUG_DRAW_BOUNDS = false;
private static final boolean DEBUG_DRAW_BOUNDS = true;
@IntDef({VISIBLE, INVISIBLE, GONE})
@Retention(RetentionPolicy.SOURCE)
@@ -38,6 +38,10 @@ public class GLTextureView extends GLView {
}
}
public Texture getTexture() {
return mTexture;
}
@Override
protected int getSuggestedMinimumWidth() {
return mTexture == null ? super.getSuggestedMinimumWidth() : mTexture.getWidth() + mPaddings.width();
@@ -61,13 +65,4 @@ public class GLTextureView extends GLView {
mTexture.draw(canvas, mSrc, mDst);
}
}
+2
View File
@@ -73,4 +73,6 @@
<dimen name="gallery_detail_thumb_width">128dp</dimen>
<dimen name="gallery_detail_thumb_height">192dp</dimen>
<dimen name="gallery_page_text">56sp</dimen>
</resources>