This commit is contained in:
seven332 committed 2015-07-23 17:23:44 +08:00
1 parent 310c510e33
commit a54f00808a
12 files changed
+101 -620

No files matched your search

@@ -29,8 +29,9 @@ import android.widget.TextView;
import com.hippo.ehviewer.Constants;
import com.hippo.ehviewer.R;
import com.hippo.yorozuya.SimpleHandler;
import com.hippo.ehviewer.util.Settings;
import com.hippo.yorozuya.Messenger;
import com.hippo.yorozuya.SimpleHandler;
import java.util.Locale;
@@ -78,8 +79,6 @@ public abstract class StatsActivity extends AppCompatActivity {
return lp;
}
protected abstract boolean isShowStats();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -96,7 +95,7 @@ public abstract class StatsActivity extends AppCompatActivity {
Messenger.getInstance().register(
Constants.MESSENGER_ID_SHOW_APP_STATUS, mReceiver);
if (isShowStats()) {
if (Settings.getShowApplicationStats()) {
mShowStats = true;
((ViewGroup) getWindow().getDecorView()).addView(mStatsTextView,
generateLayoutParams());
@@ -1,24 +0,0 @@
/*
* Copyright 2015 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 interface GalleryLoaderImpl {
void request(int index);
int size();
}
@@ -67,6 +67,10 @@ public interface GalleryProvider {
void retry();
int size();
void setPause(boolean pause);
void addGalleryProviderListener(GalleryProviderListener listener);
void removeGalleryProviderListener(GalleryProviderListener listener);
@@ -194,6 +194,22 @@ public class GallerySpider implements GalleryProvider, SpiderQueen.SpiderListene
}
}
@Override
public int size() {
if (mSpiderQueen != null) {
return mSpiderQueen.pages();
} else {
return -1;
}
}
@Override
public void setPause(boolean pause) {
if (mSpiderQueen != null) {
mSpiderQueen.setPause(pause);
}
}
public void releaseBitmap(Bitmap bitmap) {
if (mSpiderQueen != null) {
mSpiderQueen.releaseBitmap(bitmap);
@@ -136,8 +136,6 @@ public class ImageHandler {
mBitmapPool.addReusableBitmap(bitmap);
}
private boolean containFromRead(int index) {
String key = EhCacheKeyFactory.getImageKey(mGalleryBase.gid, index);
return sDiskCache.contain(key);
@@ -17,6 +17,7 @@
package com.hippo.ehviewer.gallery;
import android.graphics.Bitmap;
import android.os.Looper;
import android.os.Process;
import com.hippo.ehviewer.client.EhConfig;
@@ -202,6 +203,20 @@ public class SpiderQueen implements Runnable {
}
}
public int pages() {
if (mSpiderInfo != null) {
return mSpiderInfo.pages;
} else {
return -1;
}
}
public void setPause(boolean pause) {
if (mRender != null) {
mRender.setPause(pause);
}
}
@Override
public void run() {
Say.d(TAG, "Spider Queen start");
@@ -523,6 +538,11 @@ public class SpiderQueen implements Runnable {
return;
}
// TODO make sure onGetPages first then other listener
// 7. tell listener pages
mSpiderListener.onGetPages(spiderInfo.pages);
// 6. Make workers and render to work
ensureWorker();
mRender = new Render();
@@ -530,9 +550,6 @@ public class SpiderQueen implements Runnable {
thread.setPriority(Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// 7. tell listener pages
mSpiderListener.onGetPages(spiderInfo.pages);
// 8. Get tokens
handleToken(spiderInfo, ehConfig);
@@ -553,14 +570,6 @@ public class SpiderQueen implements Runnable {
mRender.stop();
}
public int pages() {
if (mSpiderInfo != null) {
return mSpiderInfo.pages;
} else {
return -1;
}
}
private void ensureWorker() {
mWorkerArrayLock.lock();
@@ -779,15 +788,46 @@ public class SpiderQueen implements Runnable {
private BlockingQueue<Integer> mQueue = new LinkedBlockingQueue<>();
public boolean mPauseAccess = false;
private final Object mPauseLock = new Object();
public void stop() {
mStop = true;
setPause(false);
synchronized (mRenderLock) {
mRenderLock.notify();
}
}
public void setPause(final boolean pause) {
synchronized (mPauseLock) {
if (mPauseAccess != pause) {
mPauseAccess = pause;
if (!pause) {
mPauseLock.notify();
}
}
}
}
private void waitUntilUnpaused() {
synchronized (mPauseLock) {
if (Looper.myLooper() != Looper.getMainLooper()) {
while (mPauseAccess) {
try {
mPauseLock.wait();
} catch (InterruptedException e) {
// ignored, we'll start waiting again
}
}
}
}
}
public void request(int index) {
mQueue.offer(index);
if (!mQueue.contains(index)) {
mQueue.offer(index);
}
synchronized (mRenderLock) {
mRenderLock.notify();
}
@@ -799,6 +839,8 @@ public class SpiderQueen implements Runnable {
while (!mStop) {
waitUntilUnpaused();
Integer index = mQueue.poll();
if (index == null) {
synchronized (mRenderLock) {
@@ -1,322 +0,0 @@
/*
* Copyright 2015 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.widget;
import android.content.Context;
import android.graphics.Rect;
import android.support.annotation.Nullable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.View;
import com.hippo.yorozuya.LayoutUtils;
import com.hippo.yorozuya.MathUtils;
import com.hippo.yorozuya.Say;
public class GalleryView extends RecyclerView {
private static final String TAG = GalleryView.class.getSimpleName();
private static int INTERVAL_DP = 32;
private Mode mMode;
private int mHalfInterval;
private boolean mNeedAdjustPosition;
private GalleryLayoutManager mLayoutManager;
public enum Mode {
LEFT_TO_RIGHT,
RIGHT_TO_LEFT,
TOP_TO_BOTTOM
}
public GalleryView(Context context) {
super(context);
init(context);
}
public GalleryView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
public GalleryView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
mHalfInterval = LayoutUtils.dp2pix(context, INTERVAL_DP) / 2;
mLayoutManager = new GalleryLayoutManager(context);
setLayoutManager(mLayoutManager);
addItemDecoration(new IntervalDecoration());
addOnScrollListener(new ScrollListener());
setHasFixedSize(true);
setMode(Mode.RIGHT_TO_LEFT);
}
public void setMode(Mode mode) {
mMode = mode;
if (mMode == Mode.LEFT_TO_RIGHT) {
mLayoutManager.setOrientation(HORIZONTAL);
mLayoutManager.setReverseLayout(false);
} else if (mMode == Mode.RIGHT_TO_LEFT) {
mLayoutManager.setOrientation(HORIZONTAL);
mLayoutManager.setReverseLayout(true);
} else if (mMode == Mode.TOP_TO_BOTTOM) {
mLayoutManager.setOrientation(VERTICAL);
mLayoutManager.setReverseLayout(false);
}
// Not all DecorInset will be updated at once, so do it by myself
int length = getChildCount();
for (int i = 0; i < length; i++) {
((RecyclerView.LayoutParams) getChildAt(i).getLayoutParams()).mInsetsDirty = true;
}
if (mode == Mode.LEFT_TO_RIGHT || mode == Mode.RIGHT_TO_LEFT) {
mNeedAdjustPosition = true;
}
}
@Override
public boolean fling(int velocityX, int velocityY) {
if (mMode == Mode.TOP_TO_BOTTOM) {
return super.fling(velocityX, velocityY);
} else {
return false;
}
}
public void scrollByEfficiently(int x, int y) {
if (x != 0 || y != 0) {
scrollBy(x, y);
}
}
private int size() {
return getAdapter().getItemCount();
}
// Only work for Mode.LEFT_TO_RIGHT and Mode.RIGHT_TO_LEFT
private View findCenterXView() {
int centerX = getWidth() / 2;
int length = getChildCount();
for (int i = 0; i < length; i++) {
View v = getChildAt(i);
if (v.getLeft() < centerX && v.getRight() >= centerX) {
return v;
}
}
return null;
}
// Only work for Mode.LEFT_TO_RIGHT and Mode.RIGHT_TO_LEFT
private int getOffsetToPage(int page) throws Exception {
View v = findCenterXView();
if (v == null) {
throw new Exception("Can't find center view");
}
int currentPage = getChildAdapterPosition(v);
if (currentPage == RecyclerView.NO_POSITION) {
throw new Exception("Can't find current page");
}
int d = page - currentPage;
if (mMode == Mode.RIGHT_TO_LEFT) {
d = -d;
}
return d * (mHalfInterval * 2 + getWidth()) + v.getLeft();
}
public void smoothScrollToPage(int page) {
if (mMode == Mode.TOP_TO_BOTTOM) {
smoothScrollToPosition(page);
} else {
page = MathUtils.clamp(page, 0, size() - 1);
try {
int offsetX = getOffsetToPage(page);
smoothScrollBy(offsetX, 0);
} catch (Exception e) {
Say.d(TAG, e.getMessage());
smoothScrollToPosition(page);
}
}
}
public void scrollToPage(int page) {
if (mMode == Mode.TOP_TO_BOTTOM) {
scrollToPosition(page);
} else {
page = MathUtils.clamp(page, 0, size() - 1);
try {
int offsetX = getOffsetToPage(page);
scrollByEfficiently(offsetX, 0);
} catch (Exception e) {
Say.d(TAG, e.getMessage());
scrollToPosition(page);
}
}
}
public int getCurrentPage() {
if (mMode == Mode.TOP_TO_BOTTOM) {
return mLayoutManager.findFirstVisibleItemPosition();
} else {
View v = findCenterXView();
if (v == null) {
return RecyclerView.NO_POSITION;
} else {
return getChildLayoutPosition(v);
}
}
}
class GalleryLayoutManager extends LinearLayoutManager {
public GalleryLayoutManager(Context context) {
super(context);
}
@Override
public void measureChildWithMargins(View child, int widthUsed, int heightUsed) {
// Call it to update decor
getItemDecorInsetsForChild(child);
int widthSpec;
int heightSpec;
// LayoutParams is useless
if (mMode == Mode.TOP_TO_BOTTOM) {
widthSpec = View.MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY);
heightSpec = View.MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST);
} else {
widthSpec = View.MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY);
heightSpec = View.MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.EXACTLY);
}
child.measure(widthSpec, heightSpec);
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
super.onLayoutChildren(recycler, state);
// Ensure page is in center
if (mNeedAdjustPosition) {
mNeedAdjustPosition = false;
int currentPage = getCurrentPage();
if (currentPage != RecyclerView.NO_POSITION) {
scrollToPage(currentPage);
}
}
}
}
class ScrollListener extends OnScrollListener {
private int mCurrentPage = RecyclerView.NO_POSITION;
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if (mMode == Mode.TOP_TO_BOTTOM) {
// Nothing to do
return;
}
if (newState == SCROLL_STATE_DRAGGING) {
mCurrentPage = getCurrentPage();
} else if (newState == SCROLL_STATE_IDLE) {
if (mCurrentPage != RecyclerView.NO_POSITION) {
ViewHolder viewHolder = findViewHolderForLayoutPosition(mCurrentPage);
if (viewHolder == null) {
// WTF?
Say.w(TAG, "Can't find ViewHolder when adjustPosition");
smoothScrollToPage(mCurrentPage);
} else {
View v = viewHolder.itemView;
int scrollX;
int interval = mHalfInterval * 2;
int left = v.getLeft();
int width = getWidth();
if (left > interval &&
((mMode == Mode.LEFT_TO_RIGHT && mCurrentPage > 0) ||
(mMode == Mode.RIGHT_TO_LEFT && mCurrentPage < size() - 1))) { // Scroll left
scrollX = -width - interval + left;
} else if (left < -interval &&
((mMode == Mode.LEFT_TO_RIGHT && mCurrentPage < size() - 1) ||
(mMode == Mode.RIGHT_TO_LEFT && mCurrentPage > 0))) { // Scroll right
scrollX = width + interval + left;
} else {
scrollX = left;
}
smoothScrollBy(scrollX, 0);
}
mCurrentPage = RecyclerView.NO_POSITION;
}
}
}
}
class IntervalDecoration extends RecyclerView.ItemDecoration {
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {
int index = getChildLayoutPosition(view);
if (mMode == Mode.LEFT_TO_RIGHT) {
if (index == 0) {
outRect.left = 0;
} else {
outRect.left = mHalfInterval;
}
if (index == size() - 1) {
outRect.right = 0;
} else {
outRect.right = mHalfInterval;
}
outRect.top = 0;
outRect.bottom = 0;
} else if (mMode == Mode.RIGHT_TO_LEFT) {
if (index == 0) {
outRect.right = 0;
} else {
outRect.right = mHalfInterval;
}
if (index == size() - 1) {
outRect.left = 0;
} else {
outRect.left = mHalfInterval;
}
outRect.top = 0;
outRect.bottom = 0;
} else if (mMode == Mode.TOP_TO_BOTTOM) {
if (index == 0) {
outRect.top = 0;
} else {
outRect.top = mHalfInterval;
}
if (index == size() - 1) {
outRect.bottom = 0;
} else {
outRect.bottom = mHalfInterval;
}
outRect.left = 0;
outRect.right = 0;
}
}
}
}
@@ -128,11 +128,6 @@ public final class ContentActivity extends StageActivity
}
};
@Override
protected boolean isShowStats() {
return Settings.getShowApplicationStats();
}
@SuppressLint("RtlHardcoded")
@SuppressWarnings("deprecation")
@Override
@@ -16,250 +16,7 @@
package com.hippo.ehviewer.ui;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.hippo.app.StatsActivity;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.client.data.GalleryBase;
import com.hippo.ehviewer.gallery.GalleryProvider;
import com.hippo.ehviewer.gallery.GalleryProviderListener;
import com.hippo.ehviewer.gallery.GallerySpider;
import com.hippo.ehviewer.gallery.ImageHandler;
import com.hippo.ehviewer.gallery.widget.GalleryView;
import com.hippo.util.SystemUiHelper;
import com.hippo.widget.ProgressView;
import com.hippo.yorozuya.Say;
import java.io.IOException;
// TODO Adjust RecyclerView recycle logic or Create a bitmap map here
public class GalleryActivity extends AppCompatActivity implements GalleryProviderListener {
public static final String KEY_GALLERY_BASE = "gallery_base";
private SystemUiHelper mSystemUiHelper;
private GalleryView mGalleryView;
private GalleryAdapter mAdapter;
private GallerySpider mGallerySpider;
private GalleryBase mGalleryBase;
private int mSize;
private boolean mReady = false;
private void handleIntent(Intent intent) {
if (intent == null) {
finish();
return;
}
mGalleryBase = intent.getParcelableExtra(KEY_GALLERY_BASE);
if (mGalleryBase == null) {
finish();
return;
}
try {
mGallerySpider = GallerySpider.obtain(mGalleryBase, ImageHandler.Mode.READ);
} catch (IOException e) {
throw new IllegalStateException(e); // TODO
}
mGallerySpider.addGalleryProviderListener(this);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mSystemUiHelper = new SystemUiHelper(this, SystemUiHelper.LEVEL_IMMERSIVE,
SystemUiHelper.FLAG_LAYOUT_IN_SCREEN_OLDER_DEVICES | SystemUiHelper.FLAG_IMMERSIVE_STICKY);
mSystemUiHelper.hide();
setContentView(R.layout.activity_gallery);
mGalleryView = (GalleryView) findViewById(R.id.gallery_view);
mAdapter = new GalleryAdapter();
mGalleryView.setAdapter(mAdapter);
handleIntent(getIntent());
}
@Override
protected void onDestroy() {
super.onDestroy();
mGallerySpider.removeGalleryProviderListener(this);
if (mGallerySpider != null) {
GallerySpider.release(mGallerySpider);
mGallerySpider = null;
}
// TODO free all bitmap in ImageView
}
@Override
public void onTotallyFailed(Exception e) {
e.printStackTrace();
}
@Override
public void onPartlyFailed(Exception e) {
e.printStackTrace();
}
@Override
public void onGetSize(int size) {
Say.d("TAG", "size = " + size);
mReady = true;
mSize = size;
mAdapter.notifyDataSetChanged();
}
@Override
public void onGetBitmap(int index, @Nullable Bitmap bitmap) {
GalleryHolder holder = (GalleryHolder) mGalleryView.findViewHolderForAdapterPosition(index);
if (holder == null) {
mGallerySpider.releaseBitmap(bitmap);
} else {
if (bitmap == null) {
clearDrawable(holder.imageView, getResources().getDrawable(R.drawable.ic_sad));
holder.imageView.setVisibility(View.VISIBLE);
holder.progressView.setVisibility(View.GONE);
} else {
clearDrawable(holder.imageView, new BitmapDrawable(getResources(), bitmap));
holder.imageView.setVisibility(View.VISIBLE);
holder.progressView.setVisibility(View.GONE);
}
}
}
@Override
public void onPagePercent(int index, float percent) {
GalleryHolder holder = (GalleryHolder) mGalleryView.findViewHolderForAdapterPosition(index);
if (holder != null) {
clearDrawable(holder.imageView, null);
holder.imageView.setVisibility(View.GONE);
ProgressView progressView = holder.progressView;
progressView.setVisibility(View.VISIBLE);
progressView.setIndeterminate(false);
progressView.setProgress(percent);
}
}
@Override
public void onPageSucceed(int index) {
GalleryHolder holder = (GalleryHolder) mGalleryView.findViewHolderForAdapterPosition(index);
if (holder != null) {
bind(holder, index);
}
}
@Override
public void onPageFailed(int index, Exception e) {
e.printStackTrace();
GalleryHolder holder = (GalleryHolder) mGalleryView.findViewHolderForAdapterPosition(index);
if (holder != null) {
clearDrawable(holder.imageView, null);
holder.imageView.setVisibility(View.VISIBLE);
holder.imageView.setImageDrawable(getResources().getDrawable(R.drawable.ic_sad)); // TODO
holder.progressView.setVisibility(View.GONE);
}
}
private void bind(GalleryHolder holder, int index) {
clearDrawable(holder.imageView, null);
if (mReady) {
Object result = mGallerySpider.request(index);
if (result instanceof Float) {
holder.imageView.setVisibility(View.GONE);
ProgressView progressView = holder.progressView;
progressView.setVisibility(View.VISIBLE);
progressView.setIndeterminate(false);
progressView.setProgress((Float) result);
} else if (result == GalleryProvider.RESULT_NONE) {
holder.imageView.setVisibility(View.GONE);
ProgressView progressView = holder.progressView;
progressView.setVisibility(View.VISIBLE);
progressView.setIndeterminate(true);
} else if (result == GalleryProvider.RESULT_WAIT) {
holder.imageView.setVisibility(View.GONE);
holder.progressView.setVisibility(View.GONE);
} else if (result == GalleryProvider.RESULT_FAILED) {
holder.imageView.setVisibility(View.VISIBLE);
holder.imageView.setImageDrawable(getResources().getDrawable(R.drawable.ic_sad)); // TODO
holder.progressView.setVisibility(View.GONE);
} else {
holder.imageView.setVisibility(View.VISIBLE);
holder.imageView.setImageDrawable(getResources().getDrawable(R.drawable.ic_heart)); // TODO
holder.progressView.setVisibility(View.GONE);
}
} else {
holder.imageView.setVisibility(View.GONE);
holder.progressView.setVisibility(View.VISIBLE);
holder.progressView.setIndeterminate(true);
}
}
private void clearDrawable(ImageView imageView, Drawable drawable) {
Drawable oldDrawable = imageView.getDrawable();
if (oldDrawable instanceof BitmapDrawable) {
mGallerySpider.releaseBitmap(((BitmapDrawable) oldDrawable).getBitmap());
}
imageView.setImageDrawable(drawable);
}
class GalleryHolder extends RecyclerView.ViewHolder {
public ImageView imageView;
public ProgressView progressView;
public GalleryHolder(View itemView) {
super(itemView);
imageView = (ImageView) itemView.findViewById(R.id.image);
progressView = (ProgressView) itemView.findViewById(R.id.progress);
}
}
class GalleryAdapter extends RecyclerView.Adapter<GalleryHolder> {
@Override
public GalleryHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new GalleryHolder(getLayoutInflater().inflate(
R.layout.item_gallery, parent, false));
}
@Override
public void onBindViewHolder(GalleryHolder holder, int position) {
bind(holder, position);
}
@Override
public int getItemCount() {
return mReady ? mSize : 1;
}
}
public class GalleryActivity extends StatsActivity {
}
@@ -281,7 +281,7 @@ public class GalleryDetailScene extends Scene implements View.OnClickListener,
if (v == mRead) {
Intent intent = new Intent(getStageActivity(), GalleryActivity.class);
intent.putExtra(GalleryActivity.KEY_GALLERY_BASE, mGalleryDetail);
//intent.putExtra(GalleryActivity.KEY_GALLERY_BASE, mGalleryDetail);
getStageActivity().startActivity(intent);
} else if (v == mDownload) {