Improve GalleryActivity

This commit is contained in:
seven332 committed 2016-02-16 16:37:18 +08:00
1 parent 7ad8a3afd1
commit 6f37491471
22 files changed
+620 -273

No files matched your search

@@ -18,7 +18,9 @@ package com.hippo.ehviewer;
import android.app.ActivityManager;
import android.content.Context;
import android.os.Debug;
import android.support.annotation.NonNull;
import android.util.Log;
import android.util.SparseArray;
import com.hippo.beerbelly.LruCacheEx;
@@ -33,7 +35,9 @@ import com.hippo.okhttp.CookieDB;
import com.hippo.scene.SceneApplication;
import com.hippo.text.Html;
import com.hippo.util.ReadableTime;
import com.hippo.yorozuya.FileUtils;
import com.hippo.yorozuya.IntIdGenerator;
import com.hippo.yorozuya.SimpleHandler;
import java.io.File;
import java.util.Comparator;
@@ -43,7 +47,10 @@ import okhttp3.OkHttpClient;
public class EhApplication extends SceneApplication {
private static final String TAG = EhApplication.class.getSimpleName();
private static final boolean DEBUG_CONACO = false;
private static final boolean DEBUG_NATIVE_MEMORY = false;
private IntIdGenerator mIdGenerator = new IntIdGenerator();
private SparseArray<Object> mGlobalStuffMap = new SparseArray<>();
@@ -60,11 +67,27 @@ public class EhApplication extends SceneApplication {
public void onCreate() {
super.onCreate();
GetText.initialize(this);
CookieDB.initialize(this);
StatusCodeException.initialize(this);
Settings.initialize(this);
ReadableTime.initialize(this);
Html.initialize(this);
if (DEBUG_NATIVE_MEMORY) {
debugNativeMemory();
}
}
private void debugNativeMemory() {
new Runnable() {
@Override
public void run() {
Log.i(TAG, "Native memory: " + FileUtils.humanReadableByteCount(
Debug.getNativeHeapAllocatedSize(), false));
SimpleHandler.getInstance().postDelayed(this, 3000);
}
}.run();
}
public int putGlobalStuff(@NonNull Object o) {
@@ -0,0 +1,41 @@
/*
* 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);
}
}
@@ -17,50 +17,68 @@
package com.hippo.ehviewer.gallery;
import android.os.Process;
import android.support.annotation.Nullable;
import android.util.Log;
import com.hippo.ehviewer.GetText;
import com.hippo.ehviewer.R;
import com.hippo.image.Image;
import com.hippo.yorozuya.PriorityThread;
import com.hippo.yorozuya.StringUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Stack;
import java.util.concurrent.atomic.AtomicInteger;
public class DirGalleryProvider extends GalleryProvider {
public class DirGalleryProvider extends GalleryProvider implements Runnable {
private static final String TAG = DirGalleryProvider.class.getSimpleName();
private static final AtomicInteger sIdGenerator = new AtomicInteger();
private File mDir;
private String[] mFiles;
private final File mDir;
private final Stack<Integer> mRequests = new Stack<>();
private boolean mRun = true;
@Nullable
private Thread mBgThread;
private volatile int mSize = STATE_WAIT;
private String mError;
private boolean mStarted = false;
public DirGalleryProvider(File dir) {
mDir = dir;
mFiles = mDir.list(new ImageFilter());
}
@Override
public void start() {
mRun = true;
new Decoder().start();
}
if (mStarted) {
throw new IllegalStateException("Can't start it twice");
}
mStarted = true;
@Override
public void stop() {
mRun = false;
synchronized (mRequests) {
mRequests.notify();
if (mBgThread == null || mBgThread.isInterrupted()) {
mBgThread = new PriorityThread(this, TAG + '-' + sIdGenerator.incrementAndGet(),
Process.THREAD_PRIORITY_BACKGROUND);
mBgThread.start();
}
}
@Override
public void stop() {
if (mBgThread == null || mBgThread.isInterrupted()) {
return;
}
mBgThread.interrupt();
mBgThread = null;
}
@Override
public int size() {
return mFiles != null ? mFiles.length : 0;
return mSize;
}
@Override
@@ -77,69 +95,74 @@ public class DirGalleryProvider extends GalleryProvider {
}
}
private static final String[] ENDS = {
".jpg", // Joint Photographic Experts Group
".jpeg",
".png", // Portable Network Graphics
".gif", // Graphics Interchange Format
};
@Override
public String getError() {
return mError;
}
@Override
public void run() {
// It may take a long time, so run it in new thread
String[] files = mDir.list(new ImageFilter());
if (files == null) {
mSize = STATE_ERROR;
mError = GetText.getString(R.string.error_not_folder_path);
mBgThread = null;
// Notify to to show error
notifyDataChanged();
Log.i(TAG, "ImageDecoder end with error");
return;
}
// Sort it
Arrays.sort(files);
// Set state normal and notify
mSize = files.length;
notifyDataChanged();
while (!Thread.currentThread().isInterrupted()) {
int index;
synchronized (mRequests) {
if (mRequests.isEmpty()) {
try {
mRequests.wait();
} catch (InterruptedException e) {
// Interrupted
break;
}
continue;
}
index = mRequests.pop();
}
try {
InputStream is = new FileInputStream(new File(mDir, files[index]));
Image image = Image.decode(is, false);
if (image != null) {
notifyPageSucceed(index, image);
} else {
notifyPageFailed(index, GetText.getString(R.string.error_decoding_failed));
}
} catch (FileNotFoundException e) {
notifyPageFailed(index, GetText.getString(R.string.error_not_found));
}
}
// Clear
mBgThread = null;
Log.i(TAG, "ImageDecoder end");
}
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");
return StringUtils.endsWith(filename.toLowerCase(), SUPPORT_IMAGE_EXTENSIONS);
}
}
}
@@ -0,0 +1,45 @@
/*
* 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;
public class EhGalleryProvider extends GalleryProvider {
@Override
public void start() {
}
@Override
public void stop() {
}
@Override
public int size() {
return 0;
}
@Override
public int request(int index) {
return 0;
}
@Override
public String getError() {
return null;
}
}
@@ -30,15 +30,22 @@ import java.util.List;
public abstract class GalleryProvider {
@IntDef({RESULT_FAILED, RESULT_WAIT, RESULT_ERROR})
@IntDef({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 RESULT_WAIT = 0;
public static final int RESULT_ERROR = 1;
public static final int SIZE_WAIT = -1;
public static final int STATE_WAIT = -1;
public static final int STATE_ERROR = -2;
public static final String[] SUPPORT_IMAGE_EXTENSIONS = {
".jpg", // Joint Photographic Experts Group
".jpeg",
".png", // Portable Network Graphics
".gif", // Graphics Interchange Format
};
private List<GalleryProviderListener> mGalleryProviderListeners = new ArrayList<>(2);
private Pool<NotifyTask> mNotifyTaskPool = new Pool<>(5);
@@ -49,13 +56,15 @@ public abstract class GalleryProvider {
public abstract void stop();
/**
* @return {@link #SIZE_WAIT} for wait, 0 for empty
* @return {@link #STATE_WAIT} for wait, 0 for empty
*/
public abstract int size();
@Result
public abstract int request(int index);
public abstract String getError();
public void addGalleryProviderListener(GalleryProviderListener listener) {
mGalleryProviderListeners.add(listener);
}
@@ -64,36 +73,41 @@ public abstract class GalleryProvider {
mGalleryProviderListeners.remove(listener);
}
public void notifyDataChanged() {
notify(NotifyTask.TYPE_DATA_CHANGED, 0, 0.0f, null, null);
}
public void notifyPagePercent(int index, float percent) {
notifyPage(NotifyTask.TYPE_PERCENT, index, percent, null, null);
notify(NotifyTask.TYPE_PERCENT, index, percent, null, null);
}
public void notifyPageSucceed(int index, Image image) {
notifyPage(NotifyTask.TYPE_SUCCEED, index, 0.0f, image, null);
notify(NotifyTask.TYPE_SUCCEED, index, 0.0f, image, null);
}
public void notifyPageFailed(int index, Exception e) {
notifyPage(NotifyTask.TYPE_FAILED, index, 0.0f, null, e);
public void notifyPageFailed(int index, String error) {
notify(NotifyTask.TYPE_FAILED, index, 0.0f, null, error);
}
private void notifyPage(@NotifyTask.Type int type, int index, float percent, Image image, Exception exception) {
private void notify(@NotifyTask.Type int type, int index, float percent, Image image, String error) {
NotifyTask task = mNotifyTaskPool.pop();
if (task == null) {
task = new NotifyTask(mGalleryProviderListeners, mNotifyTaskPool);
}
task.setData(type, index, percent, image, exception);
task.setData(type, index, percent, image, error);
mHandler.post(task);
}
private static class NotifyTask implements Runnable {
@IntDef({TYPE_PERCENT, TYPE_SUCCEED, TYPE_FAILED})
@IntDef({TYPE_DATA_CHANGED, 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;
public static final int TYPE_DATA_CHANGED = 0;
public static final int TYPE_PERCENT = 1;
public static final int TYPE_SUCCEED = 2;
public static final int TYPE_FAILED = 3;
private List<GalleryProviderListener> mGalleryProviderListeners;
private Pool<NotifyTask> mPool;
@@ -103,24 +117,29 @@ public abstract class GalleryProvider {
private int mIndex;
private float mPercent;
private Image mImage;
private Exception mException;
private String mError;
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) {
public void setData(@Type int type, int index, float percent, Image image, String error) {
mType = type;
mIndex = index;
mPercent = percent;
mImage = image;
mException = exception;
mError = error;
}
@Override
public void run() {
switch (mType) {
case TYPE_DATA_CHANGED:
for (int i = 0, n = mGalleryProviderListeners.size(); i < n; i++) {
mGalleryProviderListeners.get(i).onDataChanged();
}
break;
case TYPE_PERCENT:
for (int i = 0, n = mGalleryProviderListeners.size(); i < n; i++) {
mGalleryProviderListeners.get(i).onPagePercent(mIndex, mPercent);
@@ -133,14 +152,14 @@ public abstract class GalleryProvider {
break;
case TYPE_FAILED:
for (int i = 0, n = mGalleryProviderListeners.size(); i < n; i++) {
mGalleryProviderListeners.get(i).onPageFailed(mIndex, mException);
mGalleryProviderListeners.get(i).onPageFailed(mIndex, mError);
}
break;
}
// Clean data
mImage = null;
mException = null;
mError = null;
// Push back
mPool.push(this);
}
@@ -20,9 +20,11 @@ import com.hippo.image.Image;
public interface GalleryProviderListener {
void onDataChanged();
void onPagePercent(int index, float percent);
void onPageSucceed(int index, Image image);
void onPageFailed(int index, Exception e);
void onPageFailed(int index, String error);
}
@@ -0,0 +1,194 @@
/*
* 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.support.annotation.Nullable;
import android.util.Log;
import com.hippo.ehviewer.GetText;
import com.hippo.ehviewer.R;
import com.hippo.image.Image;
import com.hippo.yorozuya.PriorityThread;
import com.hippo.yorozuya.StringUtils;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Stack;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
public class ZipGalleryProvider extends GalleryProvider implements Runnable {
private static final String TAG = ZipGalleryProvider.class.getSimpleName();
private static final AtomicInteger sIdGenerator = new AtomicInteger();
private final File mFile;
private final Stack<Integer> mRequests = new Stack<>();
@Nullable
private Thread mBgThread;
private volatile int mSize = STATE_WAIT;
private String mError;
private boolean mStarted = false;
public ZipGalleryProvider(File file) {
mFile = file;
}
@Override
public void start() {
if (mStarted) {
throw new IllegalStateException("Can't start it twice");
}
mStarted = true;
if (mBgThread == null || mBgThread.isInterrupted()) {
mBgThread = new PriorityThread(this, TAG + '-' + sIdGenerator.incrementAndGet(),
Process.THREAD_PRIORITY_BACKGROUND);
mBgThread.start();
}
}
@Override
public void stop() {
if (mBgThread == null || mBgThread.isInterrupted()) {
return;
}
mBgThread.interrupt();
mBgThread = null;
}
@Override
public int size() {
return mSize;
}
@Override
public int request(int index) {
if (index < 0 || index >= mSize) {
return RESULT_ERROR;
} else {
synchronized (mRequests) {
mRequests.add(index);
mRequests.notify();
}
return RESULT_WAIT;
}
}
@Override
public String getError() {
return mError;
}
@Override
public void run() {
ZipFile zipFile = null;
try {
zipFile = new ZipFile(mFile);
} catch (ZipException e) {
mError = GetText.getString(R.string.error_invalid_zip_file);
} catch (FileNotFoundException e) {
mError = GetText.getString(R.string.error_not_found);
} catch (IOException e) {
mError = GetText.getString(R.string.error_reading_failed);
}
// Check zip file null
if (zipFile == null) {
mSize = STATE_ERROR;
if (mError == null) {
mError = GetText.getString(R.string.error_unknown);
}
mBgThread = null;
// Notify to to show error
notifyDataChanged();
Log.i(TAG, "ImageDecoder end with error");
return;
}
// Get all image name
List<String> filenames = new ArrayList<>(zipFile.size());
Enumeration<? extends ZipEntry> enumeration = zipFile.entries();
while (enumeration.hasMoreElements()) {
ZipEntry zipEntry = enumeration.nextElement();
String filename = zipEntry.getName();
if (!zipEntry.isDirectory() && StringUtils.endsWith(filename, SUPPORT_IMAGE_EXTENSIONS)) {
filenames.add(filename);
}
}
Collections.sort(filenames);
// Update size and notify changed
mSize = filenames.size();
notifyDataChanged();
while (!Thread.currentThread().isInterrupted()) {
int index;
synchronized (mRequests) {
if (mRequests.isEmpty()) {
try {
mRequests.wait();
} catch (InterruptedException e) {
// Interrupted
break;
}
continue;
}
index = mRequests.pop();
}
try {
ZipEntry zipEntry = zipFile.getEntry(filenames.get(index));
if (zipEntry != null) {
InputStream is = zipFile.getInputStream(zipEntry);
Image image = Image.decode(is, false);
if (image != null) {
notifyPageSucceed(index, image);
} else {
notifyPageFailed(index, GetText.getString(R.string.error_decoding_failed));
}
} else {
notifyPageFailed(index, GetText.getString(R.string.error_reading_failed));
}
} catch (IOException e) {
notifyPageFailed(index, GetText.getString(R.string.error_reading_failed));
}
}
// Clear
try {
zipFile.close();
} catch (IOException e) {
// Ignore
}
mBgThread = null;
Log.i(TAG, "ImageDecoder end");
}
}
@@ -16,6 +16,8 @@
package com.hippo.ehviewer.gallery.gl;
import android.content.Context;
import com.hippo.gl.glrenderer.BasicTexture;
import com.hippo.gl.glrenderer.ImageTexture;
import com.hippo.gl.glrenderer.MovableTextTexture;
@@ -27,9 +29,11 @@ import com.hippo.gl.widget.GLMovableTextView;
import com.hippo.gl.widget.GLProgressView;
import com.hippo.gl.widget.GLTextureView;
import com.hippo.image.Image;
import com.hippo.yorozuya.LayoutUtils;
public class GalleryPageView extends GLFrameLayout {
private static final int INFO_INTERVAL = 24;
public static final float PROGRESS_GONE = -1.0f;
public static final float PROGRESS_INDETERMINATE = -2.0f;
@@ -39,7 +43,7 @@ public class GalleryPageView extends GLFrameLayout {
private GLTextureView mError;
private GLProgressView mProgress;
public GalleryPageView(MovableTextTexture pageTextTexture,
public GalleryPageView(Context context, MovableTextTexture pageTextTexture,
int progressColor, int progressSize) {
// Add image
mImage = new ImageView();
@@ -50,6 +54,7 @@ public class GalleryPageView extends GLFrameLayout {
// Add other panel
mInfo = new GLLinearLayout();
mInfo.setOrientation(GLLinearLayout.VERTICAL);
mInfo.setInterval(LayoutUtils.dp2pix(context, INFO_INTERVAL));
glp = new GravityLayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
glp.gravity = Gravity.CENTER;
@@ -17,7 +17,6 @@
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;
@@ -144,8 +143,8 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
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;
mErrorSize = context.getResources().getDimension(R.dimen.text_large);
mErrorColor = context.getResources().getColor(R.color.red_500);
mPageMinHeight = LayoutUtils.dp2pix(context, PAGE_MIN_HEIGHT_IN_DP);
mInterval = LayoutUtils.dp2pix(context, INTERVAL_IN_DP);
@@ -154,7 +153,7 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
private void ensurePagerLayoutManager() {
if (mPagerLayoutManager == null) {
mPagerLayoutManager = new PagerLayoutManager(mContext, this, mInterval);
mPagerLayoutManager = new PagerLayoutManager(mContext, this);
}
}
@@ -436,7 +435,7 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
public GalleryPageView obtainPage() {
GalleryPageView page = mRecycler.obtain();
if (page == null) {
page = new GalleryPageView(mPageTextTexture, mProgressColor, mProgressSize);
page = new GalleryPageView(mContext, mPageTextTexture, mProgressColor, mProgressSize);
page.setMinimumHeight(mPageMinHeight);
}
return page;
@@ -523,12 +522,16 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
public abstract void reset();
public abstract boolean isBusy();
/**
* @return True for waiting now, layout manager
* should show a progress bar or something like it
*/
public abstract boolean isWaiting();
/**
* Null for no error
* @return Null for no error
*/
public abstract String isError();
public abstract String getError();
public abstract boolean hasNext();
@@ -29,6 +29,7 @@ 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.LayoutUtils;
import com.hippo.yorozuya.MathUtils;
import java.lang.annotation.Retention;
@@ -43,6 +44,8 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
public static final int MODE_LEFT_TO_RIGHT = 0;
public static final int MODE_RIGHT_TO_LEFT = 1;
private static final int INTERVAL = 48;
private static final Interpolator SMOOTH_SCROLLER_INTERPOLATOR = new Interpolator() {
@Override
public float getInterpolation(float t) {
@@ -76,10 +79,9 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
private SmoothScroller mSmoothScroller;
private SmoothScaler mSmoothScaler;
public PagerLayoutManager(Context context, @NonNull GalleryView galleryView,
int interval) {
public PagerLayoutManager(Context context, @NonNull GalleryView galleryView) {
super(galleryView);
mInterval = interval;
mInterval = LayoutUtils.dp2pix(context, INTERVAL);
mPageFling = new PageFling(context);
mSmoothScroller = new SmoothScroller();
@@ -239,7 +241,7 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
int width = galleryView.getWidth();
int height = galleryView.getHeight();
String errorStr = iterator.isError();
String errorStr = iterator.getError();
if (errorStr != null) {
// Remove progress and all pages
@@ -260,7 +262,7 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
// Place error view center
placeCenter(mErrorView);
} else if (iterator.isBusy()) {
} else if (iterator.isWaiting()) {
// Remove error view and all pages
removeErrorView();
removeAllPages();
@@ -138,7 +138,7 @@ public class ScrollLayoutManager extends GalleryView.LayoutManager {
int width = galleryView.getWidth();
int height = galleryView.getHeight();
String errorStr = iterator.isError();
String errorStr = iterator.getError();
if (errorStr != null) {
// Remove progress and all pages
@@ -159,7 +159,7 @@ public class ScrollLayoutManager extends GalleryView.LayoutManager {
// Place error view center
placeCenter(mErrorView);
} else if (iterator.isBusy()) {
} else if (iterator.isWaiting()) {
// Remove error view and all pages
removeErrorView();
removeAllPages();
@@ -177,6 +177,12 @@ public class ScrollLayoutManager extends GalleryView.LayoutManager {
removeProgress();
removeErrorView();
// TODO ensure first shown
int minY = (int) (-height * RESERVATIONS);
// Remove useless top view
@@ -281,6 +287,10 @@ public class ScrollLayoutManager extends GalleryView.LayoutManager {
}
iterator.reset();
// TODO Avoid page not fill bottom, but has previous
// Remove useless page
while (mPages.size() > pageSize) {
GalleryPageView page = mPages.removeLast();
@@ -16,9 +16,10 @@
package com.hippo.ehviewer.ui;
import android.content.Intent;
import android.graphics.Typeface;
import android.os.Bundle;
import android.os.Environment;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.util.SparseIntArray;
@@ -28,6 +29,7 @@ import com.hippo.ehviewer.R;
import com.hippo.ehviewer.gallery.DirGalleryProvider;
import com.hippo.ehviewer.gallery.GalleryProvider;
import com.hippo.ehviewer.gallery.GalleryProviderListener;
import com.hippo.ehviewer.gallery.ZipGalleryProvider;
import com.hippo.ehviewer.gallery.gl.GalleryPageView;
import com.hippo.ehviewer.gallery.gl.GalleryView;
import com.hippo.gl.glrenderer.ImageTexture;
@@ -41,6 +43,20 @@ import java.io.File;
public class GalleryActivity extends AppCompatActivity implements GalleryProviderListener {
public static final String ACTION_DIR = "dir";
public static final String ACTION_ZIP = "zip";
public static final String ACTION_EH = "eh";
public static final String KEY_ACTION = "action";
public static final String KEY_FILENAME = "filename";
public static final String KEY_GID = "gid";
public static final String KEY_TOKEN = "token";
private String mAction;
private String mFilename;
private int mGid;
private String mToken;
@Nullable
private GalleryView mGalleryView;
@@ -53,26 +69,82 @@ public class GalleryActivity extends AppCompatActivity implements GalleryProvide
@Nullable
private SparseIntArray mIndexIdMap;
private void buildProvider() {
if (mGalleryProvider != null) {
return;
}
if (ACTION_DIR.equals(mAction)) {
if (mFilename != null) {
mGalleryProvider = new DirGalleryProvider(new File(mFilename));
}
} else if (ACTION_ZIP.equals(mAction)) {
if (mFilename != null) {
mGalleryProvider = new ZipGalleryProvider(new File(mFilename));
}
} else if (ACTION_EH.equals(mAction)) {
}
}
private void onInit() {
Intent intent = getIntent();
if (intent == null) {
return;
}
mAction = intent.getAction();
mFilename = intent.getStringExtra(KEY_FILENAME);
mGid = intent.getIntExtra(KEY_GID, -1);
mToken = intent.getStringExtra(KEY_TOKEN);
buildProvider();
}
private void onRestore(@NonNull Bundle savedInstanceState) {
mAction = savedInstanceState.getString(KEY_ACTION);
mFilename = savedInstanceState.getString(KEY_FILENAME);
mGid = savedInstanceState.getInt(KEY_GID, -1);
mToken = savedInstanceState.getString(KEY_TOKEN);
buildProvider();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(KEY_ACTION, mAction);
outState.putString(KEY_FILENAME, mFilename);
outState.putInt(KEY_GID, mGid);
outState.putString(KEY_TOKEN, mToken);
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gallery);
GLRootView glRootView = (GLRootView) findViewById(R.id.gl_root_view);
if (savedInstanceState == null) {
onInit();
} else {
onRestore(savedInstanceState);
}
mUploader = new ImageTexture.Uploader(glRootView);
mIndexIdMap = new SparseIntArray();
mGalleryProvider = new DirGalleryProvider(new File(Environment.getExternalStorageDirectory(), "nmb/image"));
if (mGalleryProvider == null) {
finish();
return;
}
mGalleryProvider.addGalleryProviderListener(this);
mGalleryProvider.start();
setContentView(R.layout.activity_gallery);
GLRootView glRootView = (GLRootView) findViewById(R.id.gl_root_view);
mUploader = new ImageTexture.Uploader(glRootView);
mIndexIdMap = new SparseIntArray();
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);
mPageTextTexture, null, GalleryView.LAYOUT_MODE_RIGHT_TO_LEFT);
glRootView.setContentPane(mGalleryView);
}
@@ -182,6 +254,13 @@ public class GalleryActivity extends AppCompatActivity implements GalleryProvide
return mGalleryView.findPageById(id);
}
@Override
public void onDataChanged() {
if (mGalleryView != null) {
mGalleryView.onDataChanged();
}
}
@Override
public void onPagePercent(int index, float percent) {
GalleryPageView page = findPageByIndex(index);
@@ -203,18 +282,20 @@ public class GalleryActivity extends AppCompatActivity implements GalleryProvide
page.setPage(index + 1);
page.setProgress(GalleryPageView.PROGRESS_GONE);
page.setError(null, null);
} else {
image.recycle();
}
}
@Override
public void onPageFailed(int index, Exception e) {
public void onPageFailed(int index, String error) {
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);
page.setError(error, mGalleryView);
}
}
@@ -235,20 +316,23 @@ public class GalleryActivity extends AppCompatActivity implements GalleryProvide
}
@Override
public boolean isBusy() {
return mGalleryProvider == null ||
mGalleryProvider.size() == GalleryProvider.SIZE_WAIT;
public boolean isWaiting() {
return mGalleryProvider != null && mGalleryProvider.size() == GalleryProvider.STATE_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
public String getError() {
if (mGalleryProvider == null) {
return getString(R.string.error_no_provider);
} else if (mGalleryProvider.size() == GalleryProvider.STATE_ERROR) {
String error = mGalleryProvider.getError();
if (error != null) {
return error;
} else {
return getString(R.string.error_unknown);
}
} else if (mGalleryProvider.size() == 0) {
return getString(R.string.error_empty);
}
return null;
}
@@ -282,29 +366,12 @@ public class GalleryActivity extends AppCompatActivity implements GalleryProvide
@Override
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;
}
mGalleryProvider.request(mIndex);
view.showInfo();
view.setImage(null);
view.setPage(mIndex + 1);
view.setProgress(GalleryPageView.PROGRESS_INDETERMINATE);
view.setError(null, null);
}
int id = mIdGenerator.nextId();
@@ -128,6 +128,8 @@ public final class MainActivity extends StageActivity
private void onRestore(Bundle savedInstanceState) {
Log.d("TAG", "onRestore");
Log.d("TAG", "action = " + getIntent().getAction());
mNavCheckedItem = savedInstanceState.getInt(KEY_NAV_CHECKED_ITEM);
}
@@ -65,7 +65,9 @@ public class GalleryPreviewsScene extends ToolbarScene {
public final static String KEY_HAS_FIRST_REFRESH = "has_first_refresh";
private EhClient mClient;
@Nullable
private GalleryPreviewAdapter mAdapter;
@Nullable
private GalleryPreviewHelper mHelper;
private int mGid = -1;
private String mToken = null;
@@ -169,6 +171,9 @@ public class GalleryPreviewsScene extends ToolbarScene {
int id = item.getItemId();
switch (id) {
case R.id.action_go_to:
if (mHelper == null) {
return true;
}
int pages = mHelper.getPages();
if (pages > 0 && mHelper.canGoTo()) {
GoToDialogHelper helper = new GoToDialogHelper(pages, mHelper.getPageForTop());
@@ -211,14 +216,16 @@ public class GalleryPreviewsScene extends ToolbarScene {
@Override
public void onBindViewHolder(GalleryPreviewHolder holder, int position) {
GalleryPreview preview = mHelper.getDataAt(position);
holder.image.load(EhCacheKeyFactory.getLargePreviewKey(mGid, preview.index), preview.imageUrl);
holder.text.setText(String.format(Locale.US, "%d", preview.index + 1));
if (mHelper != null) {
GalleryPreview preview = mHelper.getDataAt(position);
holder.image.load(EhCacheKeyFactory.getLargePreviewKey(mGid, preview.index), preview.imageUrl);
holder.text.setText(String.format(Locale.US, "%d", preview.index + 1));
}
}
@Override
public int getItemCount() {
return mHelper.size();
return mHelper != null ? mHelper.size() : 0;
}
}
@@ -260,17 +267,23 @@ public class GalleryPreviewsScene extends ToolbarScene {
@Override
protected void notifyDataSetChanged() {
mAdapter.notifyDataSetChanged();
if (mAdapter != null) {
mAdapter.notifyDataSetChanged();
}
}
@Override
protected void notifyItemRangeRemoved(int positionStart, int itemCount) {
mAdapter.notifyItemRangeRemoved(positionStart, itemCount);
if (mAdapter != null) {
mAdapter.notifyItemRangeRemoved(positionStart, itemCount);
}
}
@Override
protected void notifyItemRangeInserted(int positionStart, int itemCount) {
mAdapter.notifyItemRangeInserted(positionStart, itemCount);
if (mAdapter != null) {
mAdapter.notifyItemRangeInserted(positionStart, itemCount);
}
}
}
@@ -376,7 +389,7 @@ public class GalleryPreviewsScene extends ToolbarScene {
@Override
public void onClick(View v) {
int page = mSlider.getProgress() - 1;
if (page >= 0 && page < mPages) {
if (page >= 0 && page < mPages && mHelper != null) {
mHelper.goTo(page);
if (mDialog != null) {
mDialog.dismiss();
@@ -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 = true;
private static final boolean DEBUG_DRAW_BOUNDS = false;
@IntDef({VISIBLE, INVISIBLE, GONE})
@Retention(RetentionPolicy.SOURCE)