package com.dozuki.ifixit.ui.guide; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import com.dozuki.ifixit.App; import com.dozuki.ifixit.R; import com.dozuki.ifixit.model.Image; import com.dozuki.ifixit.ui.guide.view.FullImageViewActivity; import com.dozuki.ifixit.util.ImageSizes; import com.dozuki.ifixit.util.PicassoUtils; import com.dozuki.ifixit.util.Utils; import com.squareup.picasso.Picasso; import com.squareup.picasso.RequestCreator; import com.squareup.picasso.Target; import java.io.File; import java.util.ArrayList; import java.util.Iterator; public class ThumbnailView extends LinearLayout { private static final String TAG = "ThumbnailView"; private ArrayList<ViewHolder> mThumbs; private FallbackImageView mMainImage; private ImageView mAddThumbButton; private boolean mShowSingle = false; private boolean mCanEdit = false; private DisplayMetrics mDisplayMetrics; private float mNavigationHeight; private float mThumbnailWidth = 0; private float mThumbnailHeight = 0; private float mMainWidth = 0; private float mMainHeight = 0; private int mThumbnailSpacing; private boolean mIsOfflineGuide; static class ViewHolder { FallbackImageView image; FrameLayout container; } private OnLongClickListener mLongClickListener; private OnClickListener mAddThumbListener; private Picasso mPicasso; private LinearLayout mThumbnailContainer; private FrameLayout mMainImageContainer; public ThumbnailView(Context context) { super(context); init(context); } public ThumbnailView(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs); } public void destroy() { mPicasso.cancelRequest((Target) mMainImage); Utils.safeStripImageView(mMainImage); for (ViewHolder view : mThumbs) { mPicasso.cancelRequest((Target) view.image); Utils.safeStripImageView(view.image); } mMainImage = null; mThumbs = null; mLongClickListener = null; mAddThumbListener = null; mPicasso = null; } private void init(Context context) { LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); inflater.inflate(R.layout.thumbnail_viewer, this, true); mThumbnailSpacing = getResources().getDimensionPixelSize(R.dimen.guide_thumbnail_spacing); mPicasso = PicassoUtils.with(getContext()); if (mCanEdit) { mAddThumbButton = (ImageView) findViewById(R.id.add_thumbnail_icon); mAddThumbButton.setVisibility(VISIBLE); } mThumbnailContainer = (LinearLayout) findViewById(R.id.thumbnail_list); mMainImageContainer = (FrameLayout) findViewById(R.id.thumbnail_main_image); mMainImageContainer.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String url = (String) v.getTag(); if (url == null || (url.equals("") || url.startsWith("."))) { return; } Context context = getContext(); context.startActivity(FullImageViewActivity.viewImage(context, url, mIsOfflineGuide)); } }); mMainImage = (FallbackImageView) mMainImageContainer.findViewById(R.id.main_image_view); mThumbs = new ArrayList<ViewHolder>(); setOrientation(App.get().inPortraitMode() ? HORIZONTAL : VERTICAL); } private void init(Context context, AttributeSet attrs) { TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ThumbnailView); mShowSingle = a.getBoolean(R.styleable.ThumbnailView_show_single, false); mCanEdit = a.getBoolean(R.styleable.ThumbnailView_can_edit, false); a.recycle(); init(context); } public void setThumbs(ArrayList<Image> images, boolean isOfflineGuide) { boolean hideOnSingleThumb = (images.size() <= 1 && !mShowSingle); mIsOfflineGuide = isOfflineGuide; calculateDimensions(hideOnSingleThumb); mThumbnailContainer.setVisibility(hideOnSingleThumb ? GONE : VISIBLE); if (!images.isEmpty()) { for (ViewHolder view : mThumbs) { mThumbnailContainer.removeView(view.container); } mThumbs.clear(); for (Image image : images) { addThumb(image); } } else { if (mAddThumbButton != null) { mAddThumbButton.setVisibility(GONE); } } if (!((Image) mThumbs.get(0).container.getTag()).isLocal()) { setCurrentThumb(((Image) mThumbs.get(0).container.getTag()).getPath()); } fitToSpace(); } public void setDefaultMainImage() { mMainImageContainer.setTag(null); mPicasso.load(R.drawable.no_image) .fit() .into((ImageView)mMainImage); } public void setAddImageMain() { mMainImage.setImageDrawable(getResources().getDrawable(R.drawable.add_photos)); mMainImage.setScaleType(ImageView.ScaleType.FIT_CENTER); mMainImageContainer.setOnClickListener(mAddThumbListener); mMainImageContainer.setTag(null); } public void setAddThumbButtonOnClick(OnClickListener listener) { if (mCanEdit) { mAddThumbListener = listener; mAddThumbButton.setOnClickListener(listener); if (mThumbs.isEmpty()) { mMainImageContainer.setOnClickListener(listener); } } } private int addThumb(Image image) { LayoutInflater inflater = (LayoutInflater) getContext().getSystemService( Context.LAYOUT_INFLATER_SERVICE); View view = inflater.inflate(R.layout.thumbnail, mThumbnailContainer, false); ViewHolder thumb = new ViewHolder(); thumb.container = (FrameLayout) view.findViewById(R.id.thumbnail_wrapper); thumb.image = (FallbackImageView) view.findViewById(R.id.thumbnail_image); thumb.container.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { for (ViewHolder view : mThumbs) { if (v.getId() == view.container.getId() && v.getTag() instanceof Image) { Image image = (Image) v.getTag(); setCurrentThumb(image.getPath()); } } } }); if (mLongClickListener != null) { thumb.container.setOnLongClickListener(mLongClickListener); } thumb.image.setImage(image); if (image.hasLocalPath()) { File file = new File(image.getLocalPath()); buildImage(mPicasso.load(file) .resize((int) (mThumbnailWidth - 0.5f), (int) (mThumbnailHeight - 0.5f)) .centerCrop(), thumb.image); buildImage(mPicasso.load(file) .resize((int) (mMainWidth - 0.5f), (int) (mMainHeight - 0.5f)) .centerCrop(), mMainImage); } else { buildImage(PicassoUtils.displayImage(mPicasso, image.getPath(ImageSizes.stepThumb), mIsOfflineGuide), thumb.image); } setThumbnailDimensions(thumb, mThumbnailHeight, mThumbnailWidth); thumb.container.setTag(image); mThumbs.add(thumb); int thumbnailPosition = mThumbs.size() - 1; mThumbnailContainer.addView(thumb.container, thumbnailPosition); if ((mThumbs.size() > 2 || mThumbs.size() < 1) && mAddThumbButton != null) { mAddThumbButton.setVisibility(GONE); } // Return the position of the newly added thumbnail return thumbnailPosition; } public void removeThumb(Object view) { Iterator<ViewHolder> it = mThumbs.iterator(); while (it.hasNext()) { ViewHolder thumbHolder = it.next(); if (thumbHolder.container == view) { it.remove(); mThumbnailContainer.removeView(thumbHolder.container); } } if ((mThumbs.size() < 3 && mThumbs.size() > 0) && mAddThumbButton != null) { mAddThumbButton.setVisibility(VISIBLE); } if (mThumbs.size() < 1) { setAddImageMain(); } else { Image image = (Image) mThumbs.get(mThumbs.size() - 1).container.getTag(); setCurrentThumb(image.getPath()); } } public void setThumbsOnLongClickListener(View.OnLongClickListener listener) { mLongClickListener = listener; for (ViewHolder thumb : mThumbs) thumb.container.setOnLongClickListener(mLongClickListener); } public void setCurrentThumb(String url) { // Set the images tag as the url before we append .{size} to it, otherwise // FullImageView is passed a smaller version of the image. mMainImageContainer.setTag(url); mMainImage.setImageUrl(url); if (url.startsWith("http")) { url = url + ImageSizes.stepMain; buildImage(PicassoUtils.displayImage(mPicasso, url, mIsOfflineGuide), mMainImage); } else { buildImage(mPicasso.load(new File(url)) .resize((int) (mMainWidth - 0.5f), (int) (mMainHeight - 0.5f)) .centerCrop(), mMainImage); } } public void setCurrentThumb(File file) { mMainImageContainer.setTag(file.getPath()); buildImage(mPicasso.load(file), mMainImage); } public void setDisplayMetrics(DisplayMetrics metrics) { mDisplayMetrics = metrics; } public void fitToSpace() { calculateDimensions((mThumbs.size() <= 1 && !mShowSingle)); setMainImageDimensions(mMainHeight, mMainWidth); if (mThumbs.size() > 0) { for (ViewHolder thumb : mThumbs) { setThumbnailDimensions(thumb, mThumbnailHeight, mThumbnailWidth); } } if (mAddThumbButton != null) { LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( (int) (mThumbnailWidth - .5f), (int) (mThumbnailHeight - .5f) ); if (!App.get().inPortraitMode()) { lp.gravity = Gravity.NO_GRAVITY; lp.setMargins(0, 0, mThumbnailSpacing, 0); } else { lp.gravity = Gravity.RIGHT; lp.setMargins(0, 0, 0, mThumbnailSpacing); } mAddThumbButton.setLayoutParams(lp); } } public void setNavigationHeight(float navHeight) { mNavigationHeight = navHeight; } private void setMainImageDimensions(float height, float width) { // Set the width and height of the main image mMainImage.getLayoutParams().height = (int) (height - 0.5f); mMainImage.getLayoutParams().width = (int) (width - 0.5f); mMainImage.setScaleType( (mThumbs.size() == 0) ? ImageView.ScaleType.CENTER_INSIDE : ImageView.ScaleType.FIT_CENTER); } private void setThumbnailDimensions(ViewHolder thumb, float height, float width) { FrameLayout.LayoutParams flp = new FrameLayout.LayoutParams( (int) (width - .5f), (int) (height - .5f) ); LinearLayout.LayoutParams llp = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); if (!App.get().inPortraitMode()) { llp.gravity = Gravity.NO_GRAVITY; llp.setMargins(0, 0, mThumbnailSpacing, 0); } else { llp.gravity = Gravity.RIGHT; llp.setMargins(0, 0, 0, mThumbnailSpacing); } thumb.image.setLayoutParams(flp); thumb.container.setLayoutParams(llp); } private void buildImage(RequestCreator builder, FallbackImageView image) { builder .error(R.drawable.no_image) .into((Target) image); } private void calculateDimensions(boolean fullScreen) { if (mMainWidth == 0 || mMainHeight == 0) { getMainImageDimensions(fullScreen); } if (mThumbnailWidth == 0 || mThumbnailHeight == 0) { getThumbnailDimensions(); } } private void getMainImageDimensions(boolean fullScreen) { if (App.get().inPortraitMode()) { float pagePadding = (getResources().getDimensionPixelSize(R.dimen.page_padding) * 2f); // If we are hiding the thumbnails when there's 0 or 1 images on the step, // the main image should expand to fill the available screen space. if (fullScreen) { mMainWidth = (mDisplayMetrics.widthPixels - pagePadding); } else { // Main image is 4/5ths of the available screen width mMainWidth = (((mDisplayMetrics.widthPixels - pagePadding - getResources().getDimensionPixelSize(R.dimen.guide_image_spacing)) / 5f) * 4f); } mMainHeight = mMainWidth * (3f / 4f); } else { mNavigationHeight += getResources().getDimensionPixelSize(R.dimen.landscape_navigation_height); mNavigationHeight += getResources().getDimensionPixelSize(R.dimen.guide_image_spacing); // Main image is 4/5ths of the available screen height mMainHeight = (((mDisplayMetrics.heightPixels - mNavigationHeight) / 5f) * 4f); mMainWidth = mMainHeight * (4f / 3f); } } private void getThumbnailDimensions() { if (App.get().inPortraitMode()) { float pagePadding = (getResources().getDimensionPixelSize(R.dimen.page_padding) * 2f) + getResources().getDimensionPixelSize(R.dimen.guide_image_spacing); // Screen height minus everything else that occupies horizontal space mThumbnailWidth = (mDisplayMetrics.widthPixels - mMainWidth - pagePadding); mThumbnailHeight = mThumbnailWidth * (3f / 4f); } else { float pagePadding = (getResources().getDimensionPixelSize(R.dimen.page_padding) * 2f); // Screen height minus everything else that occupies vertical space mThumbnailHeight = (mDisplayMetrics.heightPixels - mMainHeight - mNavigationHeight); mThumbnailWidth = (mThumbnailHeight * (4f / 3f)); } } }