add EmojiSpan that scaled w/ TextView
Fixes #3317 Closes #3605 // FREEBIE
This commit is contained in:
parent
35159ac456
commit
9b2aabfdc8
8 changed files with 51 additions and 42 deletions
|
@ -68,7 +68,7 @@
|
|||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="?conversation_item_received_text_primary_color"
|
||||
android:textColorLink="?conversation_item_received_text_primary_color"
|
||||
android:textSize="16sp"
|
||||
android:textSize="@dimen/conversation_item_body_text_size"
|
||||
android:autoLink="all"
|
||||
android:linksClickable="true" />
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@
|
|||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="?conversation_item_sent_text_primary_color"
|
||||
android:textColorLink="?conversation_item_sent_text_primary_color"
|
||||
android:textSize="16sp"
|
||||
android:textSize="@dimen/conversation_item_body_text_size"
|
||||
tools:text="Mango pickle lorem ipsum" />
|
||||
|
||||
<LinearLayout android:id="@+id/mms_download_controls"
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
android:layout_gravity="center_vertical"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<TextView android:id="@+id/title"
|
||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
<dimen name="emoji_drawer_item_padding">5dp</dimen>
|
||||
<dimen name="emoji_drawer_indicator_height">1.5dp</dimen>
|
||||
<dimen name="emoji_drawer_left_right_padding">5dp</dimen>
|
||||
<dimen name="conversation_item_body_text_size">16sp</dimen>
|
||||
<dimen name="conversation_item_date_text_size">12sp</dimen>
|
||||
<dimen name="transport_selection_popup_width">200sp</dimen>
|
||||
<dimen name="transport_selection_popup_xoff">2dp</dimen>
|
||||
|
|
|
@ -4,8 +4,8 @@ import android.graphics.drawable.Drawable;
|
|||
import android.graphics.drawable.Drawable.Callback;
|
||||
import android.text.style.ImageSpan;
|
||||
|
||||
public class InvalidatingDrawableSpan extends ImageSpan {
|
||||
public InvalidatingDrawableSpan(Drawable drawable, Callback callback) {
|
||||
public class AnimatingImageSpan extends ImageSpan {
|
||||
public AnimatingImageSpan(Drawable drawable, Callback callback) {
|
||||
super(drawable, ALIGN_BOTTOM);
|
||||
drawable.setCallback(callback);
|
||||
}
|
|
@ -9,7 +9,6 @@ import android.graphics.Paint;
|
|||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.Drawable.Callback;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build.VERSION;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
|
@ -17,6 +16,7 @@ import android.text.Spannable;
|
|||
import android.text.SpannableStringBuilder;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.util.BitmapDecodingException;
|
||||
|
@ -44,17 +44,14 @@ public class EmojiProvider {
|
|||
// |==== misc ====||======== emoticons ========||========= flags ==========|
|
||||
private static final Pattern EMOJI_RANGE = Pattern.compile("[\\u20a0-\\u32ff\\ud83c\\udc00-\\ud83d\\udeff\\udbb9\\udce5-\\udbb9\\udcee]");
|
||||
|
||||
public static final double EMOJI_FULL = 1.00;
|
||||
public static final double EMOJI_SMALL = 0.90;
|
||||
public static final int EMOJI_RAW_HEIGHT = 64;
|
||||
public static final int EMOJI_RAW_WIDTH = 64;
|
||||
public static final int EMOJI_VERT_PAD = 0;
|
||||
public static final int EMOJI_PER_ROW = 32;
|
||||
|
||||
private final Context context;
|
||||
private final double drawWidth;
|
||||
private final double drawHeight;
|
||||
private final double verticalPad;
|
||||
private final float decodeScale;
|
||||
private final float verticalPad;
|
||||
|
||||
public static EmojiProvider getInstance(Context context) {
|
||||
if (instance == null) {
|
||||
|
@ -69,11 +66,8 @@ public class EmojiProvider {
|
|||
|
||||
private EmojiProvider(Context context) {
|
||||
this.context = context.getApplicationContext();
|
||||
this.drawHeight = Math.min(context.getResources().getDimension(R.dimen.emoji_drawer_size), EMOJI_RAW_HEIGHT);
|
||||
double drawScale = drawHeight / EMOJI_RAW_HEIGHT;
|
||||
this.drawWidth = EMOJI_RAW_WIDTH * drawScale;
|
||||
this.verticalPad = EMOJI_VERT_PAD * drawScale;
|
||||
Log.w(TAG, "draw size: " + drawWidth + "x" + drawHeight);
|
||||
this.decodeScale = Math.min(1f, context.getResources().getDimension(R.dimen.emoji_drawer_size) / EMOJI_RAW_HEIGHT);
|
||||
this.verticalPad = EMOJI_VERT_PAD * this.decodeScale;
|
||||
for (EmojiPageModel page : EmojiPages.PAGES) {
|
||||
if (page.hasSpriteMap()) {
|
||||
final EmojiPageBitmap pageBitmap = new EmojiPageBitmap(page);
|
||||
|
@ -84,15 +78,15 @@ public class EmojiProvider {
|
|||
}
|
||||
}
|
||||
|
||||
public Spannable emojify(CharSequence text, Callback callback) {
|
||||
public Spannable emojify(CharSequence text, TextView tv) {
|
||||
Matcher matches = EMOJI_RANGE.matcher(text);
|
||||
SpannableStringBuilder builder = new SpannableStringBuilder(text);
|
||||
|
||||
while (matches.find()) {
|
||||
int codePoint = matches.group().codePointAt(0);
|
||||
Drawable drawable = getEmojiDrawable(codePoint, EMOJI_SMALL);
|
||||
Drawable drawable = getEmojiDrawable(codePoint);
|
||||
if (drawable != null) {
|
||||
builder.setSpan(new InvalidatingDrawableSpan(drawable, callback), matches.start(), matches.end(),
|
||||
builder.setSpan(new EmojiSpan(drawable, tv), matches.start(), matches.end(),
|
||||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
}
|
||||
|
@ -100,17 +94,16 @@ public class EmojiProvider {
|
|||
return builder;
|
||||
}
|
||||
|
||||
public Drawable getEmojiDrawable(int emojiCode, double size) {
|
||||
return getEmojiDrawable(offsets.get(emojiCode), size);
|
||||
public Drawable getEmojiDrawable(int emojiCode) {
|
||||
return getEmojiDrawable(offsets.get(emojiCode));
|
||||
}
|
||||
|
||||
private Drawable getEmojiDrawable(DrawInfo drawInfo, double size) {
|
||||
private Drawable getEmojiDrawable(DrawInfo drawInfo) {
|
||||
if (drawInfo == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final EmojiDrawable drawable = new EmojiDrawable(drawInfo, drawWidth, drawHeight);
|
||||
drawable.setBounds(0, 0, (int)(drawWidth * size), (int)(drawHeight * size));
|
||||
final EmojiDrawable drawable = new EmojiDrawable(drawInfo, decodeScale);
|
||||
drawInfo.page.get().addListener(new FutureTaskListener<Bitmap>() {
|
||||
@Override public void onSuccess(final Bitmap result) {
|
||||
Util.runOnMain(new Runnable() {
|
||||
|
@ -129,22 +122,22 @@ public class EmojiProvider {
|
|||
|
||||
public class EmojiDrawable extends Drawable {
|
||||
private final DrawInfo info;
|
||||
private final double width;
|
||||
private final double height;
|
||||
private Bitmap bmp;
|
||||
private float intrinsicWidth;
|
||||
private float intrinsicHeight;
|
||||
|
||||
@Override public int getIntrinsicWidth() {
|
||||
return (int)width;
|
||||
return (int)intrinsicWidth;
|
||||
}
|
||||
|
||||
@Override public int getIntrinsicHeight() {
|
||||
return (int)height;
|
||||
return (int)intrinsicHeight;
|
||||
}
|
||||
|
||||
public EmojiDrawable(DrawInfo info, double width, double height) {
|
||||
public EmojiDrawable(DrawInfo info, float decodeScale) {
|
||||
this.info = info;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.intrinsicWidth = EMOJI_RAW_WIDTH * decodeScale;
|
||||
this.intrinsicHeight = EMOJI_RAW_HEIGHT * decodeScale;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -157,10 +150,10 @@ public class EmojiProvider {
|
|||
final int row_index = info.index % EMOJI_PER_ROW;
|
||||
|
||||
canvas.drawBitmap(bmp,
|
||||
new Rect((int)(row_index * width),
|
||||
(int)(row * height + row * verticalPad),
|
||||
(int)((row_index + 1) * width),
|
||||
(int)((row + 1) * height + row * verticalPad)),
|
||||
new Rect((int)(row_index * intrinsicWidth),
|
||||
(int)(row * intrinsicHeight + row * verticalPad),
|
||||
(int)((row_index + 1) * intrinsicWidth),
|
||||
(int)((row + 1) * intrinsicHeight + row * verticalPad)),
|
||||
getBounds(),
|
||||
paint);
|
||||
}
|
||||
|
@ -253,7 +246,7 @@ public class EmojiProvider {
|
|||
try {
|
||||
final InputStream measureStream = context.getAssets().open(model.getSprite());
|
||||
final InputStream bitmapStream = context.getAssets().open(model.getSprite());
|
||||
final Bitmap bitmap = BitmapUtil.createScaledBitmap(measureStream, bitmapStream, (float) drawHeight / (float) EMOJI_RAW_HEIGHT);
|
||||
final Bitmap bitmap = BitmapUtil.createScaledBitmap(measureStream, bitmapStream, decodeScale);
|
||||
bitmapReference = new SoftReference<>(bitmap);
|
||||
Log.w(TAG, "onPageLoaded(" + model.getSprite() + ")");
|
||||
return bitmap;
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
package org.thoughtcrime.securesms.components.emoji;
|
||||
|
||||
import android.graphics.Paint.FontMetricsInt;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
|
||||
public class EmojiSpan extends AnimatingImageSpan {
|
||||
public EmojiSpan(@NonNull Drawable drawable, @NonNull TextView tv) {
|
||||
super(drawable, tv);
|
||||
FontMetricsInt fm = tv.getPaint().getFontMetricsInt();
|
||||
final int size = fm != null ? Math.abs(fm.descent) + Math.abs(fm.ascent)
|
||||
: tv.getResources().getDimensionPixelSize(R.dimen.conversation_item_body_text_size);
|
||||
getDrawable().setBounds(0, 0, size, size);
|
||||
}
|
||||
}
|
|
@ -1,13 +1,10 @@
|
|||
package org.thoughtcrime.securesms.components.emoji;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
@ -37,8 +34,7 @@ public class EmojiView extends View implements Drawable.Callback {
|
|||
public void setEmoji(String emoji) {
|
||||
this.emoji = emoji;
|
||||
this.drawable = EmojiProvider.getInstance(getContext())
|
||||
.getEmojiDrawable(Character.codePointAt(emoji, 0),
|
||||
EmojiProvider.EMOJI_FULL);
|
||||
.getEmojiDrawable(Character.codePointAt(emoji, 0));
|
||||
postInvalidate();
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue