Only display one highres version at a time.

tempwork
Floens 10 years ago
parent 639d5cd8d3
commit 29f564ad95
  1. 89
      Clover/app/src/main/java/org/floens/chan/core/presenter/ImageViewerPresenter.java
  2. 2
      Clover/app/src/main/java/org/floens/chan/core/presenter/ThreadPresenter.java
  3. 7
      Clover/app/src/main/java/org/floens/chan/ui/controller/ImageViewerController.java
  4. 99
      Clover/app/src/main/java/org/floens/chan/ui/view/MultiImageView.java
  5. 32
      Clover/app/src/main/java/org/floens/chan/ui/view/OptionalSwipeViewPager.java
  6. 2
      Clover/app/src/main/res/layout/controller_image_viewer.xml

@ -1,16 +1,20 @@
package org.floens.chan.core.presenter;
import android.support.v4.view.ViewPager;
import android.util.Log;
import org.floens.chan.core.model.PostImage;
import org.floens.chan.core.settings.ChanSettings;
import org.floens.chan.ui.view.MultiImageView;
import org.floens.chan.utils.Logger;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class ImageViewerPresenter implements MultiImageView.Callback, ViewPager.OnPageChangeListener {
private static final String TAG = "ImageViewerPresenter";
private final Callback callback;
private final boolean imageAutoLoad = ChanSettings.imageAutoLoad.get();
@ -18,21 +22,25 @@ public class ImageViewerPresenter implements MultiImageView.Callback, ViewPager.
private boolean entering = true;
private boolean exiting = false;
private List<PostImage> images;
private int selectedIndex;
private boolean initalLowResLoaded = false;
private int selectedPosition;
// Disables swiping until the view pager is visible
private boolean viewPagerVisible = false;
private boolean changeViewsOnInTransitionEnd = false;
public ImageViewerPresenter(Callback callback) {
this.callback = callback;
}
public void showImages(List<PostImage> images, int index) {
public void showImages(List<PostImage> images, int position) {
this.images = images;
selectedIndex = index;
selectedPosition = position;
Logger.test("showImages position " + position);
// Do this before the view is measured, to avoid it to always loading the first two pages
callback.setPagerItems(images, selectedIndex);
callback.setImageMode(images.get(selectedIndex), MultiImageView.Mode.LOWRES);
callback.setPagerItems(images, selectedPosition);
callback.setImageMode(images.get(selectedPosition), MultiImageView.Mode.LOWRES);
}
public void onViewMeasured() {
@ -60,14 +68,15 @@ public class ImageViewerPresenter implements MultiImageView.Callback, ViewPager.
@Override
public void onPageSelected(int position) {
selectedIndex = position;
if (initalLowResLoaded) {
for (PostImage other : getOther(selectedIndex)) {
callback.setImageMode(other, MultiImageView.Mode.LOWRES);
}
callback.setImageMode(images.get(selectedIndex), MultiImageView.Mode.LOWRES);
Logger.test("onPageSelected " + selectedPosition + ", " + position);
if (!viewPagerVisible) {
return;
}
// onModeLoaded will handle the else case
selectedPosition = position;
onPageSwipedTo(position);
}
@Override
@ -83,8 +92,8 @@ public class ImageViewerPresenter implements MultiImageView.Callback, ViewPager.
if (mode == MultiImageView.Mode.LOWRES) {
// lowres is requested at the beginning of the transition,
// the lowres is loaded before the in transition or after
if (!initalLowResLoaded) {
initalLowResLoaded = true;
if (!viewPagerVisible) {
viewPagerVisible = true;
if (!entering) {
// Entering transition was already ended, switch now
callback.setPreviewVisibility(false);
@ -94,24 +103,49 @@ public class ImageViewerPresenter implements MultiImageView.Callback, ViewPager.
changeViewsOnInTransitionEnd = true;
}
// Transition ended or not, request loading the other side views to lowres
for (PostImage other : getOther(selectedIndex)) {
for (PostImage other : getOther(selectedPosition, false)) {
callback.setImageMode(other, MultiImageView.Mode.LOWRES);
}
// selectedIndex can be different than the initial one because of page changes before onModeLoaded was called,
// request a load of the current selectedIndex one here
callback.setImageMode(images.get(selectedIndex), MultiImageView.Mode.LOWRES);
onLowResInCenter();
} else {
if (multiImageView.getPostImage() == images.get(selectedPosition)) {
Log.i(TAG, "Loading high res from a onModeLoaded");
onLowResInCenter();
}
}
}
}
// Initial load or not, transitioning or not, load the high res when the user setting says so after the low res
if (imageAutoLoad) {
multiImageView.setMode(MultiImageView.Mode.BIGIMAGE);
}
private void onPageSwipedTo(int position) {
for (PostImage other : getOther(position, false)) {
callback.setImageMode(other, MultiImageView.Mode.LOWRES);
}
// Already in LOWRES mode
if (callback.getImageMode(images.get(selectedPosition)) == MultiImageView.Mode.LOWRES) {
Log.i(TAG, "Loading high res from a swipe");
onLowResInCenter();
}
// Else let onModeChange handle it
}
// Called from either a page swipe caused a lowres image to the center or an
// onModeLoaded when a unloaded image was swiped to the center earlier
private void onLowResInCenter() {
PostImage postImage = images.get(selectedPosition);
if (postImage.type == PostImage.Type.STATIC) {
callback.setImageMode(postImage, MultiImageView.Mode.BIGIMAGE);
} else {
// todo
}
}
@Override
public void onTap(MultiImageView multiImageView) {
onExit();
// Don't mistake a swipe from a user when the pager is disabled as a tap
if (viewPagerVisible) {
onExit();
}
}
@Override
@ -134,11 +168,14 @@ public class ImageViewerPresenter implements MultiImageView.Callback, ViewPager.
}
private List<PostImage> getOther(int position) {
List<PostImage> other = new ArrayList<>(2);
private List<PostImage> getOther(int position, boolean all) {
List<PostImage> other = new ArrayList<>(3);
if (position - 1 >= 0) {
other.add(images.get(position - 1));
}
if (all) {
other.add(images.get(position));
}
if (position + 1 < images.size()) {
other.add(images.get(position + 1));
}

@ -143,7 +143,7 @@ public class ThreadPresenter implements ChanLoader.ChanLoaderCallback, PostAdapt
if (item.hasImage) {
images.add(new PostImage(item.thumbnailUrl, item.imageUrl, item.filename, item.ext, item.imageWidth, item.imageHeight));
if (item.no == post.no) {
index = i;
index = images.size() - 1;
}
}
}

@ -11,7 +11,6 @@ import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Build;
import android.support.v4.view.ViewPager;
import android.view.View;
import android.view.Window;
import android.view.animation.DecelerateInterpolator;
@ -24,6 +23,7 @@ import org.floens.chan.core.presenter.ImageViewerPresenter;
import org.floens.chan.ui.adapter.ImageViewerAdapter;
import org.floens.chan.ui.toolbar.Toolbar;
import org.floens.chan.ui.view.ClippingImageView;
import org.floens.chan.ui.view.OptionalSwipeViewPager;
import org.floens.chan.ui.view.MultiImageView;
import org.floens.chan.utils.AndroidUtils;
import org.floens.chan.utils.AnimationUtils;
@ -47,7 +47,7 @@ public class ImageViewerController extends Controller implements View.OnClickLis
private final Toolbar toolbar;
private ClippingImageView previewImage;
private ViewPager pager;
private OptionalSwipeViewPager pager;
public ImageViewerController(Context context, Toolbar toolbar) {
super(context);
@ -65,7 +65,7 @@ public class ImageViewerController extends Controller implements View.OnClickLis
view = inflateRes(R.layout.controller_image_viewer);
view.setOnClickListener(this);
previewImage = (ClippingImageView) view.findViewById(R.id.preview_image);
pager = (ViewPager) view.findViewById(R.id.pager);
pager = (OptionalSwipeViewPager) view.findViewById(R.id.pager);
pager.setOnPageChangeListener(presenter);
AndroidUtils.waitForMeasure(view, new AndroidUtils.OnMeasuredCallback() {
@ -102,6 +102,7 @@ public class ImageViewerController extends Controller implements View.OnClickLis
public void setPagerVisiblity(boolean visible) {
pager.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
pager.setSwipingEnabled(visible);
}
public void setPagerItems(List<PostImage> images, int initialIndex) {

@ -26,6 +26,7 @@ import android.net.Uri;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.Toast;
import android.widget.VideoView;
@ -33,6 +34,7 @@ import android.widget.VideoView;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.ImageLoader.ImageContainer;
import com.koushikdutta.async.future.Future;
import com.koushikdutta.ion.Response;
import org.floens.chan.ChanApplication;
import org.floens.chan.R;
@ -48,7 +50,7 @@ import java.io.IOException;
import pl.droidsonroids.gif.GifDrawable;
import pl.droidsonroids.gif.GifImageView;
public class MultiImageView extends LoadView implements View.OnClickListener {
public class MultiImageView extends FrameLayout implements View.OnClickListener {
public enum Mode {
UNLOADED, LOWRES, BIGIMAGE
}
@ -61,7 +63,11 @@ public class MultiImageView extends LoadView implements View.OnClickListener {
private Mode mode = Mode.UNLOADED;
private boolean thumbnailNeeded = true;
private Future<?> request;
private boolean hasContent = false;
private ImageContainer thumbnailRequest;
private Future<Response<File>> bigImageRequest;
private Future<Response<File>> gifRequest;
private Future<Response<File>> videoRequest;
private VideoView videoView;
@ -95,9 +101,10 @@ public class MultiImageView extends LoadView implements View.OnClickListener {
public void setMode(Mode mode) {
if (this.mode != mode) {
final Mode previousTargetMode = this.mode;
this.mode = mode;
Logger.d(TAG, "Changing mode from " + previousTargetMode + "to " + mode + " for " + postImage.thumbnailUrl);
if (mode == Mode.LOWRES) {
Logger.d(TAG, "Changing mode to LOWRES for " + postImage.thumbnailUrl);
AndroidUtils.waitForMeasure(this, new AndroidUtils.OnMeasuredCallback() {
@Override
public boolean onMeasured(View view) {
@ -106,10 +113,14 @@ public class MultiImageView extends LoadView implements View.OnClickListener {
}
});
} else if (mode == Mode.BIGIMAGE) {
Logger.d(TAG, "Changing mode to BIGIMAGE for " + postImage.thumbnailUrl);
// Always done after at least LOWRES, so the view is measured
if (postImage.type == PostImage.Type.STATIC) {
setBigImage(postImage.imageUrl);
AndroidUtils.waitForMeasure(this, new AndroidUtils.OnMeasuredCallback() {
@Override
public boolean onMeasured(View view) {
setBigImage(postImage.imageUrl);
return false;
}
});
} else {
Logger.e(TAG, "postImage type not STATIC, not changing to BIGIMAGE mode!");
}
@ -132,25 +143,32 @@ public class MultiImageView extends LoadView implements View.OnClickListener {
}
// Also use volley for the thumbnails
ChanApplication.getVolleyImageLoader().get(thumbnailUrl, new com.android.volley.toolbox.ImageLoader.ImageListener() {
thumbnailRequest = ChanApplication.getVolleyImageLoader().get(thumbnailUrl, new com.android.volley.toolbox.ImageLoader.ImageListener() {
@Override
public void onErrorResponse(VolleyError error) {
thumbnailRequest = null;
onError();
}
@Override
public void onResponse(ImageContainer response, boolean isImmediate) {
if (response.getBitmap() != null && thumbnailNeeded) {
thumbnailRequest = null;
if (response.getBitmap() != null && (!hasContent || mode == Mode.LOWRES)) {
ImageView thumbnail = new ImageView(getContext());
thumbnail.setImageBitmap(response.getBitmap());
thumbnail.setLayoutParams(AndroidUtils.MATCH_PARAMS);
setView(thumbnail, false);
callback.onModeLoaded(MultiImageView.this, Mode.LOWRES);
onModeLoaded(Mode.LOWRES, thumbnail);
}
}
}, getWidth(), getHeight());
}
private void cancelThumbnail() {
if (thumbnailRequest != null) {
thumbnailRequest.cancelRequest();
thumbnailRequest = null;
}
}
public void setBigImage(String imageUrl) {
if (getWidth() == 0 || getHeight() == 0) {
Logger.e(TAG, "getWidth() or getHeight() returned 0, not loading big image");
@ -158,7 +176,7 @@ public class MultiImageView extends LoadView implements View.OnClickListener {
}
callback.setProgress(this, true);
request = ChanApplication.getFileCache().downloadFile(getContext(), imageUrl, new FileCache.DownloadedCallback() {
bigImageRequest = ChanApplication.getFileCache().downloadFile(getContext(), imageUrl, new FileCache.DownloadedCallback() {
@Override
public void onProgress(long downloaded, long total, boolean done) {
if (done) {
@ -171,11 +189,13 @@ public class MultiImageView extends LoadView implements View.OnClickListener {
@Override
public void onSuccess(File file) {
bigImageRequest = null;
setBigImageFile(file);
}
@Override
public void onFail(boolean notFound) {
bigImageRequest = null;
if (notFound) {
onNotFoundError();
} else {
@ -195,10 +215,10 @@ public class MultiImageView extends LoadView implements View.OnClickListener {
image.setInitCallback(new CustomScaleImageView.InitedCallback() {
@Override
public void onInit() {
removeAllViews();
addView(image);
callback.setProgress(MultiImageView.this, false);
callback.onModeLoaded(MultiImageView.this, Mode.BIGIMAGE);
if (!hasContent || mode == Mode.BIGIMAGE) {
callback.setProgress(MultiImageView.this, false);
onModeLoaded(Mode.BIGIMAGE, image);
}
}
@Override
@ -208,6 +228,13 @@ public class MultiImageView extends LoadView implements View.OnClickListener {
});
}
private void cancelBigImage() {
if (bigImageRequest != null) {
bigImageRequest.cancel();
bigImageRequest = null;
}
}
public void setGif(String gifUrl) {
if (getWidth() == 0 || getHeight() == 0) {
Logger.e(TAG, "getWidth() or getHeight() returned 0, not loading");
@ -215,7 +242,7 @@ public class MultiImageView extends LoadView implements View.OnClickListener {
}
callback.setProgress(this, true);
request = ChanApplication.getFileCache().downloadFile(getContext(), gifUrl, new FileCache.DownloadedCallback() {
gifRequest = ChanApplication.getFileCache().downloadFile(getContext(), gifUrl, new FileCache.DownloadedCallback() {
@Override
public void onProgress(long downloaded, long total, boolean done) {
if (done) {
@ -229,11 +256,13 @@ public class MultiImageView extends LoadView implements View.OnClickListener {
@Override
public void onSuccess(File file) {
gifRequest = null;
setGifFile(file);
}
@Override
public void onFail(boolean notFound) {
gifRequest = null;
if (notFound) {
onNotFoundError();
} else {
@ -261,12 +290,12 @@ public class MultiImageView extends LoadView implements View.OnClickListener {
GifImageView view = new GifImageView(getContext());
view.setImageDrawable(drawable);
view.setLayoutParams(AndroidUtils.MATCH_PARAMS);
setView(view, false);
setView(view);
}
public void setVideo(String videoUrl) {
callback.setProgress(this, true);
request = ChanApplication.getFileCache().downloadFile(getContext(), videoUrl, new FileCache.DownloadedCallback() {
videoRequest = ChanApplication.getFileCache().downloadFile(getContext(), videoUrl, new FileCache.DownloadedCallback() {
@Override
public void onProgress(long downloaded, long total, boolean done) {
if (done) {
@ -280,11 +309,13 @@ public class MultiImageView extends LoadView implements View.OnClickListener {
@Override
public void onSuccess(File file) {
videoRequest = null;
setVideoFile(file);
}
@Override
public void onFail(boolean notFound) {
videoRequest = null;
if (notFound) {
onNotFoundError();
} else {
@ -334,7 +365,7 @@ public class MultiImageView extends LoadView implements View.OnClickListener {
videoView.setVideoPath(file.getAbsolutePath());
setView(videoView, false);
setView(videoView);
videoView.start();
}
@ -360,8 +391,14 @@ public class MultiImageView extends LoadView implements View.OnClickListener {
}
public void cancelLoad() {
if (request != null) {
request.cancel(true);
if (bigImageRequest != null) {
bigImageRequest.cancel();
}
if (gifRequest != null) {
gifRequest.cancel();
}
if (videoRequest != null) {
videoRequest.cancel();
}
}
@ -370,6 +407,24 @@ public class MultiImageView extends LoadView implements View.OnClickListener {
callback.onTap(this);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
cancelLoad();
}
private void setView(View view) {
removeAllViews();
addView(view, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
}
private void onModeLoaded(Mode mode, View view) {
removeAllViews();
addView(view, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
hasContent = true;
callback.onModeLoaded(this, mode);
}
public static interface Callback {
public void onTap(MultiImageView multiImageView);

@ -0,0 +1,32 @@
package org.floens.chan.ui.view;
import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
public class OptionalSwipeViewPager extends ViewPager {
private boolean swipingEnabled;
public OptionalSwipeViewPager(Context context) {
super(context);
}
public OptionalSwipeViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
return swipingEnabled && super.onTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return swipingEnabled && super.onInterceptTouchEvent(ev);
}
public void setSwipingEnabled(boolean swipingEnabled) {
this.swipingEnabled = swipingEnabled;
}
}

@ -8,7 +8,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.v4.view.ViewPager
<org.floens.chan.ui.view.OptionalSwipeViewPager
android:id="@+id/pager"
android:visibility="invisible"
android:layout_width="match_parent"

Loading…
Cancel
Save