package org.thoughtcrime.securesms.components.emoji;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Paint.FontMetricsInt;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.AppCompatTextView;
import android.text.TextUtils;
import android.text.TextUtils.TruncateAt;
import android.util.AttributeSet;
import android.util.TypedValue;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.emoji.EmojiProvider.EmojiDrawable;
import org.thoughtcrime.securesms.components.emoji.parsing.EmojiParser;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ViewUtil;
public class EmojiTextView extends AppCompatTextView {
private final boolean scaleEmojis;
private CharSequence source;
private boolean needsEllipsizing;
private float originalFontSize;
public EmojiTextView(Context context) {
this(context, null);
}
public EmojiTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public EmojiTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.EmojiTextView, 0, 0);
scaleEmojis = a.getBoolean(R.styleable.EmojiTextView_scaleEmojis, false);
a.recycle();
a = context.obtainStyledAttributes(attrs, new int[]{android.R.attr.textSize});
originalFontSize = a.getDimensionPixelSize(0, 0);
a.recycle();
}
@Override public void setText(@Nullable CharSequence text, BufferType type) {
EmojiProvider provider = EmojiProvider.getInstance(getContext());
EmojiParser.CandidateList candidates = provider.getCandidates(text);
if (scaleEmojis && candidates != null && candidates.allEmojis) {
int emojis = candidates.size();
float scale = 1.0f;
if (emojis <= 8) scale += 0.25f;
if (emojis <= 6) scale += 0.25f;
if (emojis <= 4) scale += 0.25f;
if (emojis <= 2) scale += 0.25f;
super.setTextSize(TypedValue.COMPLEX_UNIT_PX, originalFontSize * scale);
} else if (scaleEmojis) {
super.setTextSize(TypedValue.COMPLEX_UNIT_PX, originalFontSize);
}
if (useSystemEmoji()) {
super.setText(text, type);
return;
}
source = EmojiProvider.getInstance(getContext()).emojify(candidates, text, this);
setTextEllipsized(source);
}
private boolean useSystemEmoji() {
return TextSecurePreferences.isSystemEmojiPreferred(getContext());
}
private void setTextEllipsized(final @Nullable CharSequence source) {
super.setText(needsEllipsizing ? ViewUtil.ellipsize(source, this) : source, BufferType.SPANNABLE);
}
@Override public void invalidateDrawable(@NonNull Drawable drawable) {
if (drawable instanceof EmojiDrawable) invalidate();
else super.invalidateDrawable(drawable);
}
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int size = MeasureSpec.getSize(widthMeasureSpec);
final int mode = MeasureSpec.getMode(widthMeasureSpec);
if (!useSystemEmoji() &&
getEllipsize() == TruncateAt.END &&
!TextUtils.isEmpty(source) &&
(mode == MeasureSpec.AT_MOST || mode == MeasureSpec.EXACTLY) &&
getPaint().breakText(source, 0, source.length()-1, true, size, null) != source.length())
{
needsEllipsizing = true;
FontMetricsInt font = getPaint().getFontMetricsInt();
super.onMeasure(MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(Math.abs(font.top - font.bottom), MeasureSpec.EXACTLY));
} else {
needsEllipsizing = false;
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
@Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
if (changed && !useSystemEmoji()) setTextEllipsized(source);
super.onLayout(changed, left, top, right, bottom);
}
@Override
public void setTextSize(float size) {
setTextSize(TypedValue.COMPLEX_UNIT_SP, size);
}
@Override
public void setTextSize(int unit, float size) {
this.originalFontSize = TypedValue.applyDimension(unit, size, getResources().getDisplayMetrics());
super.setTextSize(unit, size);
}
}