Signal-Android/src/org/thoughtcrime/securesms/components/ConversationItemThumbnail.java
Greyson Parrelli 8f551c8b32 Fix various redesign issues with Android 4.x.
In particular, there were many issues with drawing corners.
Unfortunately, there's no pretty way to get masking working on every
Android version, so we have to switch back to using custom backgrounds
and then using multiple masking methods depending on Android version.

Also, I had to remove attr references in drawables. They crash on 4.x.
2018-07-18 16:53:36 -07:00

192 lines
6.5 KiB
Java

package org.thoughtcrime.securesms.components;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import android.widget.ImageView;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.mms.SlideClickListener;
import org.thoughtcrime.securesms.util.ThemeUtil;
public class ConversationItemThumbnail extends FrameLayout {
private static final String TAG = ConversationItemThumbnail.class.getSimpleName();
private static final Paint LIGHT_THEME_OUTLINE_PAINT = new Paint();
private static final Paint DARK_THEME_OUTLINE_PAINT = new Paint();
static {
LIGHT_THEME_OUTLINE_PAINT.setColor(Color.argb((int) (255 * 0.2), 0, 0, 0));
LIGHT_THEME_OUTLINE_PAINT.setStyle(Paint.Style.STROKE);
LIGHT_THEME_OUTLINE_PAINT.setStrokeWidth(1f);
LIGHT_THEME_OUTLINE_PAINT.setAntiAlias(true);
DARK_THEME_OUTLINE_PAINT.setColor(Color.argb((int) (255 * 0.2), 255, 255, 255));
DARK_THEME_OUTLINE_PAINT.setStyle(Paint.Style.STROKE);
DARK_THEME_OUTLINE_PAINT.setStrokeWidth(1f);
DARK_THEME_OUTLINE_PAINT.setAntiAlias(true);
}
private final float[] radii = new float[8];
private final RectF bounds = new RectF();
private final Path corners = new Path();
private ThumbnailView thumbnail;
private ImageView shade;
private ConversationItemFooter footer;
private Paint outlinePaint;
private CornerMask cornerMask;
public ConversationItemThumbnail(Context context) {
super(context);
init(null);
}
public ConversationItemThumbnail(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public ConversationItemThumbnail(final Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs);
}
private void init(@Nullable AttributeSet attrs) {
inflate(getContext(), R.layout.conversation_item_thumbnail, this);
this.thumbnail = findViewById(R.id.conversation_thumbnail_image);
this.shade = findViewById(R.id.conversation_thumbnail_shade);
this.footer = findViewById(R.id.conversation_thumbnail_footer);
this.outlinePaint = ThemeUtil.isDarkTheme(getContext()) ? DARK_THEME_OUTLINE_PAINT : LIGHT_THEME_OUTLINE_PAINT;
this.cornerMask = new CornerMask(this);
setTouchDelegate(thumbnail.getTouchDelegate());
if (attrs != null) {
TypedArray typedArray = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.ConversationItemThumbnail, 0, 0);
thumbnail.setBounds(typedArray.getDimensionPixelSize(R.styleable.ConversationItemThumbnail_conversationThumbnail_minWidth, 0),
typedArray.getDimensionPixelSize(R.styleable.ConversationItemThumbnail_conversationThumbnail_maxWidth, 0),
typedArray.getDimensionPixelSize(R.styleable.ConversationItemThumbnail_conversationThumbnail_minHeight, 0),
typedArray.getDimensionPixelSize(R.styleable.ConversationItemThumbnail_conversationThumbnail_maxHeight, 0));
typedArray.recycle();
}
}
@SuppressWarnings("SuspiciousNameCombination")
@Override
protected void dispatchDraw(Canvas canvas) {
if (cornerMask.isLegacy()) {
cornerMask.mask(canvas);
}
super.dispatchDraw(canvas);
if (!cornerMask.isLegacy()) {
cornerMask.mask(canvas);
}
final float halfStrokeWidth = outlinePaint.getStrokeWidth() / 2;
bounds.left = halfStrokeWidth;
bounds.top = halfStrokeWidth;
bounds.right = canvas.getWidth() - halfStrokeWidth;
bounds.bottom = canvas.getHeight() - halfStrokeWidth;
corners.reset();
corners.addRoundRect(bounds, radii, Path.Direction.CW);
canvas.drawPath(corners, outlinePaint);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (getMeasuredWidth() != thumbnail.getMeasuredWidth()) {
getLayoutParams().width = shade.getLayoutParams().width = thumbnail.getMeasuredWidth();
measure(widthMeasureSpec, heightMeasureSpec);
}
}
@Override
public void setFocusable(boolean focusable) {
thumbnail.setFocusable(focusable);
}
@Override
public void setClickable(boolean clickable) {
thumbnail.setClickable(clickable);
}
@Override
public void setOnLongClickListener(@Nullable OnLongClickListener l) {
thumbnail.setOnLongClickListener(l);
}
public void showShade(boolean show) {
shade.setVisibility(show ? VISIBLE : GONE);
forceLayout();
}
public void setOutlineCorners(int topLeft, int topRight, int bottomRight, int bottomLeft) {
radii[0] = radii[1] = topLeft;
radii[2] = radii[3] = topRight;
radii[4] = radii[5] = bottomRight;
radii[6] = radii[7] = bottomLeft;
cornerMask.setRadii(topLeft, topRight, bottomRight, bottomLeft);
}
public ConversationItemFooter getFooter() {
return footer;
}
@UiThread
public void setImageResource(@NonNull GlideRequests glideRequests, @NonNull Slide slide,
boolean showControls, boolean isPreview)
{
thumbnail.setImageResource(glideRequests, slide, showControls, isPreview);
}
@UiThread
public void setImageResource(@NonNull GlideRequests glideRequests, @NonNull Slide slide,
boolean showControls, boolean isPreview, int naturalWidth,
int naturalHeight)
{
thumbnail.setImageResource(glideRequests, slide, showControls, isPreview, naturalWidth, naturalHeight);
}
public void setImageResource(@NonNull GlideRequests glideRequests, @NonNull Uri uri) {
thumbnail.setImageResource(glideRequests, uri);
}
public void setThumbnailClickListener(SlideClickListener listener) {
thumbnail.setThumbnailClickListener(listener);
}
public void setDownloadClickListener(SlideClickListener listener) {
thumbnail.setDownloadClickListener(listener);
}
public void clear(GlideRequests glideRequests) {
thumbnail.clear(glideRequests);
}
public void showProgressSpinner() {
thumbnail.showProgressSpinner();
}
}