Switched to new emoji lookup pattern, added rendering support.
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 7.0 KiB |
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.5 KiB |
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
@ -51,6 +51,7 @@ import org.thoughtcrime.securesms.mms.Slide;
|
||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.service.SendReceiveService;
|
||||
import org.thoughtcrime.securesms.util.Emoji;
|
||||
import org.thoughtcrime.securesms.util.FutureTaskListener;
|
||||
import org.thoughtcrime.securesms.util.ListenableFutureTask;
|
||||
|
||||
@ -165,7 +166,8 @@ public class ConversationItem extends LinearLayout {
|
||||
/// MessageRecord Attribute Parsers
|
||||
|
||||
private void setBodyText(MessageRecord messageRecord) {
|
||||
bodyText.setText(messageRecord.getDisplayBody(), TextView.BufferType.SPANNABLE);
|
||||
bodyText.setText(Emoji.getInstance(context).emojify(messageRecord.getDisplayBody(), Emoji.EMOJI_LARGE),
|
||||
TextView.BufferType.SPANNABLE);
|
||||
}
|
||||
|
||||
private void setContactPhoto(MessageRecord messageRecord) {
|
||||
|
@ -19,7 +19,6 @@ package org.thoughtcrime.securesms;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Typeface;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
@ -41,6 +40,7 @@ import android.widget.TextView;
|
||||
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
import org.thoughtcrime.securesms.util.Emoji;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@ -103,7 +103,9 @@ public class ConversationListItem extends RelativeLayout
|
||||
|
||||
this.recipients.addListener(this);
|
||||
this.fromView.setText(formatFrom(recipients, count, read));
|
||||
this.subjectView.setText(thread.getDisplayBody(), TextView.BufferType.SPANNABLE);
|
||||
this.subjectView.setText(Emoji.getInstance(context).emojify(thread.getDisplayBody(),
|
||||
Emoji.EMOJI_SMALL),
|
||||
TextView.BufferType.SPANNABLE);
|
||||
|
||||
if (thread.getDate() > 0)
|
||||
this.dateView.setText(DateUtils.getRelativeTimeSpanString(getContext(), thread.getDate(), false));
|
||||
|
@ -24,6 +24,7 @@ import android.widget.TextView;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.util.Emoji;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class EmojiDrawer extends FrameLayout {
|
||||
@ -32,6 +33,7 @@ public class EmojiDrawer extends FrameLayout {
|
||||
private FrameLayout recentEmojiGridLayout;
|
||||
|
||||
private EditText composeText;
|
||||
private Emoji emoji;
|
||||
|
||||
public EmojiDrawer(Context context) {
|
||||
super(context);
|
||||
@ -57,6 +59,7 @@ public class EmojiDrawer extends FrameLayout {
|
||||
}
|
||||
|
||||
private void initialize() {
|
||||
this.emoji = Emoji.getInstance(getContext());
|
||||
LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
inflater.inflate(R.layout.emoji_drawer, this, true);
|
||||
|
||||
@ -79,14 +82,14 @@ public class EmojiDrawer extends FrameLayout {
|
||||
private class EmojiClickListener implements AdapterView.OnItemClickListener {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
int start = composeText.getSelectionStart();
|
||||
int end = composeText.getSelectionEnd ();
|
||||
String emoji = Emoji.EMOJI_ASSET_CODE_MAP.get(Emoji.EMOJI_ASSETS.get(position));
|
||||
int start = composeText.getSelectionStart();
|
||||
int end = composeText.getSelectionEnd ();
|
||||
String characters = emoji.getEmojiUnicode(position);
|
||||
|
||||
composeText.getText().replace(Math.min(start, end), Math.max(start, end),
|
||||
emoji, 0, emoji.length());
|
||||
characters, 0, characters.length());
|
||||
|
||||
composeText.setText(Emoji.emojify(getContext(), composeText.getText().toString()),
|
||||
composeText.setText(emoji.emojify(composeText.getText().toString()),
|
||||
TextView.BufferType.SPANNABLE);
|
||||
|
||||
composeText.setSelection(end+2);
|
||||
@ -97,7 +100,7 @@ public class EmojiDrawer extends FrameLayout {
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return Emoji.EMOJI_ASSETS.size();
|
||||
return emoji.getEmojiAssetCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -112,25 +115,19 @@ public class EmojiDrawer extends FrameLayout {
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
try {
|
||||
String asset = Emoji.EMOJI_ASSETS.get(position);
|
||||
Drawable drawable = Drawable.createFromStream(getContext().getAssets().open(asset + ".png"), null);
|
||||
Drawable drawable = emoji.getEmojiDrawable(position);
|
||||
|
||||
if (convertView != null && convertView instanceof ImageView) {
|
||||
((ImageView)convertView).setImageDrawable(drawable);
|
||||
return convertView;
|
||||
} else {
|
||||
ImageView imageView = new ImageView(getContext());
|
||||
imageView.setImageDrawable(drawable);
|
||||
return imageView;
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
throw new AssertionError(ioe);
|
||||
if (convertView != null && convertView instanceof ImageView) {
|
||||
((ImageView)convertView).setImageDrawable(drawable);
|
||||
return convertView;
|
||||
} else {
|
||||
ImageView imageView = new ImageView(getContext());
|
||||
imageView.setImageDrawable(drawable);
|
||||
return imageView;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class EmojiPagerAdapter extends PagerAdapter {
|
||||
|
||||
@Override
|
||||
|
@ -7,170 +7,100 @@ import android.text.SpannableString;
|
||||
import android.text.style.ImageSpan;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class Emoji {
|
||||
|
||||
public static final HashMap<String, String> EMOJI_ASSET_CODE_MAP = new HashMap<String, String>();
|
||||
public static final HashMap<Pattern, String> EMOJI_CODE_ASSET_MAP = new HashMap<Pattern, String>();
|
||||
private static Emoji instance = null;
|
||||
|
||||
public static final ArrayList<String> EMOJI_ASSETS = new ArrayList<String>() {{
|
||||
add("1f601");
|
||||
add("1f602");
|
||||
add("1f603");
|
||||
add("1f604");
|
||||
add("1f605");
|
||||
add("1f606");
|
||||
add("1f609");
|
||||
add("1f60a");
|
||||
add("1f60b");
|
||||
add("1f60c");
|
||||
add("1f60d");
|
||||
add("1f60f");
|
||||
add("1f612");
|
||||
add("1f613");
|
||||
add("1f614");
|
||||
add("1f616");
|
||||
add("1f618");
|
||||
add("1f61a");
|
||||
add("1f61c");
|
||||
add("1f61d");
|
||||
add("1f61e");
|
||||
add("1f620");
|
||||
add("1f621");
|
||||
add("1f622");
|
||||
add("1f623");
|
||||
add("1f624");
|
||||
add("1f625");
|
||||
add("1f628");
|
||||
add("1f629");
|
||||
add("1f62a");
|
||||
add("1f62b");
|
||||
add("1f62d");
|
||||
add("1f630");
|
||||
add("1f631");
|
||||
add("1f632");
|
||||
add("1f633");
|
||||
add("1f635");
|
||||
add("1f637");
|
||||
|
||||
add("1f638");
|
||||
add("1f639");
|
||||
add("1f63a");
|
||||
add("1f63b");
|
||||
add("1f63c");
|
||||
add("1f63d");
|
||||
add("1f63e");
|
||||
add("1f63f");
|
||||
add("1f640");
|
||||
add("1f645");
|
||||
add("1f646");
|
||||
add("1f647");
|
||||
add("1f648");
|
||||
add("1f649");
|
||||
add("1f64a");
|
||||
add("1f64b");
|
||||
add("1f64c");
|
||||
add("1f64d");
|
||||
add("1f64e");
|
||||
add("1f64f");
|
||||
}};
|
||||
|
||||
public static ArrayList<String> EMOJI_CODES = new ArrayList<String>() {{
|
||||
add("\ud83d\ude01");
|
||||
add("\ud83d\ude02");
|
||||
add("\ud83d\ude03");
|
||||
add("\ud83d\ude04");
|
||||
add("\ud83d\ude05");
|
||||
add("\ud83d\ude06");
|
||||
add("\ud83d\ude09");
|
||||
add("\ud83d\ude0a");
|
||||
add("\ud83d\ude0b");
|
||||
add("\ud83d\ude0c");
|
||||
add("\ud83d\ude0d");
|
||||
add("\ud83d\ude0f");
|
||||
add("\ud83d\ude12");
|
||||
add("\ud83d\ude13");
|
||||
add("\ud83d\ude14");
|
||||
add("\ud83d\ude16");
|
||||
add("\ud83d\ude18");
|
||||
add("\ud83d\ude1a");
|
||||
add("\ud83d\ude1c");
|
||||
add("\ud83d\ude1d");
|
||||
add("\ud83d\ude1e");
|
||||
add("\ud83d\ude20");
|
||||
add("\ud83d\ude21");
|
||||
add("\ud83d\ude22");
|
||||
add("\ud83d\ude23");
|
||||
add("\ud83d\ude24");
|
||||
add("\ud83d\ude25");
|
||||
add("\ud83d\ude28");
|
||||
add("\ud83d\ude29");
|
||||
add("\ud83d\ude2a");
|
||||
add("\ud83d\ude2b");
|
||||
add("\ud83d\ude2d");
|
||||
add("\ud83d\ude30");
|
||||
add("\ud83d\ude31");
|
||||
add("\ud83d\ude32");
|
||||
add("\ud83d\ude33");
|
||||
add("\ud83d\ude35");
|
||||
add("\ud83d\ude37");
|
||||
|
||||
add("\ud83d\ude38");
|
||||
add("\ud83d\ude39");
|
||||
add("\ud83d\ude3a");
|
||||
add("\ud83d\ude3b");
|
||||
add("\ud83d\ude3c");
|
||||
add("\ud83d\ude3d");
|
||||
add("\ud83d\ude3e");
|
||||
add("\ud83d\ude3f");
|
||||
add("\ud83d\ude40");
|
||||
add("\ud83d\ude45");
|
||||
add("\ud83d\ude46");
|
||||
add("\ud83d\ude47");
|
||||
add("\ud83d\ude48");
|
||||
add("\ud83d\ude49");
|
||||
add("\ud83d\ude4a");
|
||||
add("\ud83d\ude4b");
|
||||
add("\ud83d\ude4c");
|
||||
add("\ud83d\ude4d");
|
||||
add("\ud83d\ude4e");
|
||||
add("\ud83d\ude4f");
|
||||
}};
|
||||
|
||||
static {
|
||||
for (int i=0;i<EMOJI_ASSETS.size();i++) {
|
||||
EMOJI_ASSET_CODE_MAP.put(EMOJI_ASSETS.get(i), EMOJI_CODES.get(i));
|
||||
EMOJI_CODE_ASSET_MAP.put(Pattern.compile(EMOJI_CODES.get(i)), EMOJI_ASSETS.get(i));
|
||||
public synchronized static Emoji getInstance(Context context) {
|
||||
if (instance == null) {
|
||||
instance = new Emoji(context);
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static Spannable emojify(Context context, String text) {
|
||||
try {
|
||||
Spannable spannable = new SpannableString(text);
|
||||
private static final Pattern EMOJI_RANGE = Pattern.compile("[\ud83d\ude01-\ud83d\ude4f]");
|
||||
public static final double EMOJI_LARGE = 1;
|
||||
public static final double EMOJI_SMALL = 0.7;
|
||||
|
||||
for (Map.Entry<Pattern, String> entry : EMOJI_CODE_ASSET_MAP.entrySet()) {
|
||||
Matcher matcher = entry.getKey().matcher(spannable);
|
||||
private final Context context;
|
||||
private final String[] emojiAssets;
|
||||
private final Set<String> emojiAssetsSet;
|
||||
|
||||
while (matcher.find()) {
|
||||
Drawable asset = Drawable.createFromStream(context.getAssets().open(entry.getValue() + ".png"), null);
|
||||
asset.setBounds(0, 0, asset.getIntrinsicWidth(), asset.getIntrinsicHeight());
|
||||
private Emoji(Context context) {
|
||||
this.context = context.getApplicationContext();
|
||||
this.emojiAssets = initializeEmojiAssets();
|
||||
this.emojiAssetsSet = new HashSet<String>();
|
||||
|
||||
Collections.addAll(this.emojiAssetsSet, emojiAssets);
|
||||
}
|
||||
|
||||
public int getEmojiAssetCount() {
|
||||
return emojiAssets.length;
|
||||
}
|
||||
|
||||
public String getEmojiUnicode(int position) {
|
||||
String hexString = emojiAssets[position].split("\\.")[0];
|
||||
Integer unicodePoint = Integer.parseInt(hexString, 16);
|
||||
return new String(Character.toChars(unicodePoint));
|
||||
}
|
||||
|
||||
public Drawable getEmojiDrawable(int position) {
|
||||
return getEmojiDrawable(emojiAssets[position]);
|
||||
}
|
||||
|
||||
public SpannableString emojify(String text) {
|
||||
return emojify(new SpannableString(text), EMOJI_LARGE);
|
||||
}
|
||||
|
||||
public SpannableString emojify(SpannableString text, double size) {
|
||||
if (text.toString().contains("\ud83d")) {
|
||||
|
||||
Matcher matches = EMOJI_RANGE.matcher(text);
|
||||
|
||||
while (matches.find()) {
|
||||
String resource = Integer.toHexString(matches.group().codePointAt(0)) + ".png";
|
||||
|
||||
if (emojiAssetsSet.contains(resource)) {
|
||||
Drawable drawable = getEmojiDrawable(resource);
|
||||
drawable.setBounds(0, 0, (int)(drawable.getIntrinsicWidth()*size),
|
||||
(int)(drawable.getIntrinsicHeight()*size));
|
||||
|
||||
|
||||
ImageSpan imageSpan = new ImageSpan(drawable, ImageSpan.ALIGN_BOTTOM);
|
||||
text.setSpan(imageSpan, matches.start(), matches.end(),
|
||||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
|
||||
ImageSpan imageSpan = new ImageSpan(asset, ImageSpan.ALIGN_BASELINE);
|
||||
Log.w("Emoji", "Replacing text with: " + imageSpan);
|
||||
spannable.setSpan(imageSpan,matcher.start(), matcher.end(),
|
||||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return spannable;
|
||||
return text;
|
||||
}
|
||||
|
||||
private Drawable getEmojiDrawable(String assetName) {
|
||||
try {
|
||||
return Drawable.createFromStream(context.getAssets().open("emoji" + File.separator + assetName), null);
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private String[] initializeEmojiAssets() {
|
||||
try {
|
||||
return context.getAssets().list("emoji");
|
||||
} catch (IOException e) {
|
||||
Log.w("Emoji", e);
|
||||
return new String[0];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|