package org.wordpress.android.ui.reader.views;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.ImageLoader.ImageContainer;
import org.wordpress.android.R;
import org.wordpress.android.WordPress;
import org.wordpress.android.ui.reader.utils.ReaderUtils;
import org.wordpress.android.util.AppLog;
import org.wordpress.android.util.DisplayUtils;
import org.wordpress.android.util.PhotonUtils;
import uk.co.senab.photoview.PhotoViewAttacher;
/**
* used by ReaderPhotoViewerActivity to show full-width images - based on Volley's ImageView
* but adds pinch/zoom and the ability to first load a lo-res version of the image
*/
public class ReaderPhotoView extends RelativeLayout {
public interface PhotoViewListener {
void onTapPhotoView();
}
private PhotoViewListener mPhotoViewListener;
private String mLoResImageUrl;
private String mHiResImageUrl;
private ImageContainer mLoResContainer;
private ImageContainer mHiResContainer;
private final ImageView mImageView;
private final ProgressBar mProgress;
private final TextView mTxtError;
private boolean mIsInitialLayout = true;
public ReaderPhotoView(Context context) {
this(context, null);
}
public ReaderPhotoView(Context context, AttributeSet attrs) {
super(context, attrs);
inflate(context, R.layout.reader_photo_view, this);
// ImageView which contains the downloaded image
mImageView = (ImageView) findViewById(R.id.image_photo);
// error text that appears when download fails
mTxtError = (TextView) findViewById(R.id.text_error);
// progress bar which appears while downloading
mProgress = (ProgressBar) findViewById(R.id.progress_loading);
}
/**
* @param imageUrl the url of the image to load
* @param hiResWidth maximum width of the full-size image
* @param isPrivate whether this is an image from a private blog
* @param listener listener for taps on this view
*/
public void setImageUrl(String imageUrl,
int hiResWidth,
boolean isPrivate,
PhotoViewListener listener) {
int loResWidth = (int) (hiResWidth * 0.10f);
mLoResImageUrl = ReaderUtils.getResizedImageUrl(imageUrl, loResWidth, 0, isPrivate, PhotonUtils.Quality.LOW);
mHiResImageUrl = ReaderUtils.getResizedImageUrl(imageUrl, hiResWidth, 0, isPrivate, PhotonUtils.Quality.MEDIUM);
mPhotoViewListener = listener;
loadLoResImage();
}
private boolean isRequestingUrl(ImageContainer container, String url) {
return (container != null
&& container.getRequestUrl() != null
&& container.getRequestUrl().equals(url));
}
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
private boolean hasLayout() {
// if the view's bounds aren't known yet, and this is not a wrap-content/wrap-content
// view, hold off on loading the image.
if (getWidth() == 0 && getHeight() == 0) {
boolean isFullyWrapContent = getLayoutParams() != null
&& getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT
&& getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT;
if (!isFullyWrapContent) {
return false;
}
}
return true;
}
private void loadLoResImage() {
if (!hasLayout() || TextUtils.isEmpty(mLoResImageUrl)) {
return;
}
// skip if this same image url is already being loaded
if (isRequestingUrl(mLoResContainer, mLoResImageUrl)) {
AppLog.d(AppLog.T.READER, "reader photo > already requesting lo-res");
return;
}
Point pt = DisplayUtils.getDisplayPixelSize(this.getContext());
int maxSize = Math.min(pt.x, pt.y);
showProgress();
mLoResContainer = WordPress.sImageLoader.get(mLoResImageUrl,
new ImageLoader.ImageListener() {
@Override
public void onErrorResponse(VolleyError error) {
AppLog.e(AppLog.T.READER, error);
hideProgress();
showError();
}
@Override
public void onResponse(final ImageContainer response, boolean isImmediate) {
post(new Runnable() {
@Override
public void run() {
handleResponse(response.getBitmap(), true);
}
});
}
}, maxSize, maxSize);
}
private void loadHiResImage() {
if (!hasLayout() || TextUtils.isEmpty(mHiResImageUrl)) {
return;
}
if (isRequestingUrl(mHiResContainer, mHiResImageUrl)) {
AppLog.d(AppLog.T.READER, "reader photo > already requesting hi-res");
return;
}
Point pt = DisplayUtils.getDisplayPixelSize(this.getContext());
int maxSize = Math.max(pt.x, pt.y);
mHiResContainer = WordPress.sImageLoader.get(mHiResImageUrl,
new ImageLoader.ImageListener() {
@Override
public void onErrorResponse(VolleyError error) {
AppLog.e(AppLog.T.READER, error);
}
@Override
public void onResponse(final ImageContainer response, boolean isImmediate) {
post(new Runnable() {
@Override
public void run() {
handleResponse(response.getBitmap(), false);
}
});
}
}, maxSize, maxSize);
}
private void handleResponse(Bitmap bitmap, boolean isLoRes) {
if (bitmap != null) {
hideProgress();
// show the bitmap and attach the pinch/zoom handler
mImageView.setImageBitmap(bitmap);
setAttacher();
// load hi-res image if this was the lo-res one
if (isLoRes && !mLoResImageUrl.equals(mHiResImageUrl)) {
loadHiResImage();
}
}
}
private void setAttacher() {
PhotoViewAttacher attacher = new PhotoViewAttacher(mImageView);
attacher.setOnPhotoTapListener(new PhotoViewAttacher.OnPhotoTapListener() {
@Override
public void onPhotoTap(View view, float v, float v2) {
if (mPhotoViewListener != null) {
mPhotoViewListener.onTapPhotoView();
}
}
});
attacher.setOnViewTapListener(new PhotoViewAttacher.OnViewTapListener() {
@Override
public void onViewTap(View view, float v, float v2) {
if (mPhotoViewListener != null) {
mPhotoViewListener.onTapPhotoView();
}
}
});
}
private void showError() {
hideProgress();
if (mTxtError != null) {
mTxtError.setVisibility(View.VISIBLE);
}
}
private void showProgress() {
if (mProgress != null) {
mProgress.setVisibility(View.VISIBLE);
}
}
private void hideProgress() {
if (mProgress != null) {
mProgress.setVisibility(View.GONE);
}
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (!isInEditMode()) {
if (mIsInitialLayout) {
mIsInitialLayout = false;
AppLog.d(AppLog.T.READER, "reader photo > initial layout");
post(new Runnable() {
@Override
public void run() {
loadLoResImage();
}
});
}
}
}
@Override
protected void onDetachedFromWindow() {
if (mLoResContainer != null || mHiResContainer != null) {
mImageView.setImageDrawable(null);
}
if (mLoResContainer != null) {
mLoResContainer.cancelRequest();
mLoResContainer = null;
}
if (mHiResContainer != null) {
mHiResContainer.cancelRequest();
mHiResContainer = null;
}
mIsInitialLayout = true;
super.onDetachedFromWindow();
}
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
invalidate();
}
}