package com.vaguehope.onosendai.widget; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; import android.util.TypedValue; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; import com.vaguehope.onosendai.R; import com.vaguehope.onosendai.images.ImageLoadRequest; import com.vaguehope.onosendai.images.ImageLoadRequest.ImageLoadListener; import com.vaguehope.onosendai.util.MutableState; public class PendingImage extends FrameLayout { private final ExpandingFixedWidthImageView image; private final ProgressBar prg; private final TextView status; private final ExpandingImageLoadListener imageLoadListener; public PendingImage (final Context context, final AttributeSet attrs) { this(context, attrs, 0); } public PendingImage (final Context context, final AttributeSet attrs, final int defStyle) { super(context, attrs, defStyle); final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PendingImage); final int maxHeightPixels = a.getDimensionPixelSize(R.styleable.PendingImage_maxHeight, -1) - getPaddingTop() - getPaddingBottom(); a.recycle(); this.prg = new ProgressBar(context, null, android.R.attr.progressBarStyleHorizontal); addView(this.prg); this.status = new TextView(context); this.status.setLayoutParams(new FrameLayout.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM)); this.status.setPadding( this.status.getPaddingLeft() + dipToPixels(context, 10), this.status.getPaddingTop(), this.status.getPaddingRight() + dipToPixels(context, 10), this.status.getPaddingBottom() + dipToPixels(context, 20)); addView(this.status); this.image = new ExpandingFixedWidthImageView(context, this.prg, this.status, maxHeightPixels); this.image.setupImageView(); this.image.setVisibility(View.GONE); addView(this.image); this.imageLoadListener = new ExpandingImageLoadListener(this.image, this.status, this.prg); this.imageLoadListener.imageFetchProgress(0, 0); } public ImageView getImage () { return this.image; } public ImageLoadListener getImageLoadListener () { return this.imageLoadListener; } public void setExpandedTracker (final MutableState<String, Boolean> expandedTracker) { this.imageLoadListener.setExpandedTracker(expandedTracker); this.image.setExpandedTracker(expandedTracker); } private static class ExpandingImageLoadListener implements ImageLoadListener { private final ExpandingFixedWidthImageView image; private final TextView status; private final ProgressBar prg; private MutableState<String, Boolean> expandedTracker; public ExpandingImageLoadListener (final ExpandingFixedWidthImageView image, final TextView status, final ProgressBar prg) { this.image = image; this.status = status; this.prg = prg; } public void setExpandedTracker (final MutableState<String, Boolean> expandedTracker) { this.expandedTracker = expandedTracker; } @Override public void imageLoadProgress (final String msg) { this.status.setText(msg); } @Override public void imageFetchProgress (final int progress, final int total) { if (total > 0) { if (this.prg.isIndeterminate()) { this.prg.setIndeterminate(false); this.prg.setLayoutParams(new FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER)); } this.prg.setMax(total); this.prg.setProgress(progress); } else { if (!this.prg.isIndeterminate()) { this.prg.setIndeterminate(true); this.prg.setLayoutParams(new FrameLayout.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER)); } } } @Override public void imagePreShow (final ImageLoadRequest req) { final Boolean expanded = this.expandedTracker != null ? this.expandedTracker.get(req.getUrl()) : null; this.image.setExpanded(expanded != null ? expanded : false); } @Override public void imageLoaded (final ImageLoadRequest req) { if (this.image.getVisibility() != View.VISIBLE) this.image.setVisibility(View.VISIBLE); if (this.prg.getVisibility() != View.GONE) this.prg.setVisibility(View.GONE); if (this.status.getVisibility() != View.GONE) this.status.setVisibility(View.GONE); } @Override public void imageLoadFailed (final ImageLoadRequest req, final String errMsg) { imageLoadProgress(errMsg); } } private static class ExpandingFixedWidthImageView extends FixedWidthImageView { private final ProgressBar prg; private final TextView status; private final int maxHeightPixels; private final GoFullHeightListener goFullHeightClickListener = new GoFullHeightListener(this); public ExpandingFixedWidthImageView (final Context context, final ProgressBar prg, final TextView status, final int maxHeightPixels) { super(context); this.status = status; this.maxHeightPixels = maxHeightPixels; this.prg = prg; } public void setExpandedTracker (final MutableState<String, Boolean> expandedTracker) { this.goFullHeightClickListener.setExpandedTracker(expandedTracker); } public void setupImageView () { if (this.maxHeightPixels > 0) { setImageLimitedHeight(); } else { setImageFullHeight(); } } public void setExpanded (final boolean expanded) { if (this.maxHeightPixels > 0) { if (expanded) { setImageFullHeight(); } else { setImageLimitedHeight(); } } } public void setImageLimitedHeight () { setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, this.maxHeightPixels)); setScaleType(ScaleType.CENTER_CROP); setMaxHeight(this.maxHeightPixels); setClickable(true); setOnClickListener(this.goFullHeightClickListener); } public void setImageFullHeight () { setMaxHeight(-1); setOnClickListener(null); setClickable(false); setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); setScaleType(ScaleType.FIT_CENTER); setAdjustViewBounds(true); } // XXX these are icky hacks to get 'show pending' and 'show image' events. @Override public void setImageResource (final int resId) { if (resId == R.drawable.question_blue) { super.setImageDrawable(null); setVisibility(View.GONE); this.prg.setVisibility(View.VISIBLE); this.status.setVisibility(View.VISIBLE); } else if (resId == R.drawable.exclamation_red) { super.setImageDrawable(null); setVisibility(View.GONE); this.prg.setVisibility(View.GONE); this.status.setVisibility(View.VISIBLE); } else { setExpanded(false); super.setImageResource(resId); setVisibility(View.VISIBLE); this.prg.setVisibility(View.GONE); this.status.setVisibility(View.GONE); } } } private static class GoFullHeightListener implements OnClickListener { private final ExpandingFixedWidthImageView image; private MutableState<String, Boolean> expandedTracker; public GoFullHeightListener (final ExpandingFixedWidthImageView image) { this.image = image; } public void setExpandedTracker (final MutableState<String, Boolean> expandedTracker) { this.expandedTracker = expandedTracker; } @Override public void onClick (final View v) { this.image.setImageFullHeight(); if (this.expandedTracker != null) { final String url = (String) this.image.getTag(R.id.imageLoaded); if (url != null) this.expandedTracker.put(url, Boolean.TRUE); } } } private static int dipToPixels (final Context context, final int a) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, a, context.getResources().getDisplayMetrics()); } }