Create emoji plugin
1
markwon-emoji/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/build
|
50
markwon-emoji/build.gradle
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
plugins {
|
||||||
|
id 'com.android.library'
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion 31
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
minSdkVersion 21
|
||||||
|
targetSdkVersion 31
|
||||||
|
versionCode 1
|
||||||
|
versionName "1.0"
|
||||||
|
|
||||||
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
consumerProguardFiles "consumer-rules.pro"
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
minifyEnabled false
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
|
||||||
|
api project(':markwon-core')
|
||||||
|
implementation 'com.google.code.gson:gson:2.8.6'
|
||||||
|
|
||||||
|
|
||||||
|
deps.with {
|
||||||
|
// add a compileOnly dependency, so if this artifact is present
|
||||||
|
// we will try to obtain a SpanFactory for a Strikethrough node and use
|
||||||
|
// it to be consistent with markdown (please note that we do not use markwon plugin
|
||||||
|
// for that in case if different implementation is used)
|
||||||
|
compileOnly it['commonmark-strikethrough']
|
||||||
|
|
||||||
|
testImplementation it['ix-java']
|
||||||
|
}
|
||||||
|
|
||||||
|
deps.test.with {
|
||||||
|
testImplementation it['junit']
|
||||||
|
testImplementation it['robolectric']
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package io.noties.markwon.emoji.ext;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry;
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instrumented test, which will execute on an Android device.
|
||||||
|
*
|
||||||
|
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||||
|
*/
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class ExampleInstrumentedTest {
|
||||||
|
@Test
|
||||||
|
public void useAppContext() {
|
||||||
|
// Context of the app under test.
|
||||||
|
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||||
|
assertEquals("io.noties.markwon.emoji.ext.test", appContext.getPackageName());
|
||||||
|
}
|
||||||
|
}
|
5
markwon-emoji/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="io.noties.markwon.emoji.ext">
|
||||||
|
|
||||||
|
</manifest>
|
26819
markwon-emoji/src/main/assets/emoji.json
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
package io.noties.markwon.emoji.ext;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.text.style.ImageSpan;
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
|
||||||
|
public class CenterSpan extends ImageSpan {
|
||||||
|
private WeakReference<Drawable> mDrawableRef;
|
||||||
|
|
||||||
|
public CenterSpan(Context context, final int drawableRes) {
|
||||||
|
super(context, drawableRes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CenterSpan(Drawable drawable) {
|
||||||
|
super(drawable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSize(Paint paint, CharSequence text, int start, int end,
|
||||||
|
Paint.FontMetricsInt fontMetricsInt) {
|
||||||
|
Drawable drawable = getDrawable();
|
||||||
|
Rect rect = drawable.getBounds();
|
||||||
|
if (fontMetricsInt != null) {
|
||||||
|
Paint.FontMetricsInt fmPaint = paint.getFontMetricsInt();
|
||||||
|
int fontHeight = fmPaint.descent - fmPaint.ascent;
|
||||||
|
int drHeight = rect.bottom - rect.top;
|
||||||
|
int centerY = fmPaint.ascent + fontHeight / 2;
|
||||||
|
|
||||||
|
fontMetricsInt.ascent = centerY - drHeight / 2;
|
||||||
|
fontMetricsInt.top = fontMetricsInt.ascent;
|
||||||
|
fontMetricsInt.bottom = centerY + drHeight / 2;
|
||||||
|
fontMetricsInt.descent = fontMetricsInt.bottom;
|
||||||
|
}
|
||||||
|
return rect.right;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void draw(Canvas canvas, CharSequence text, int start, int end,
|
||||||
|
float x, int top, int y, int bottom, Paint paint) {
|
||||||
|
|
||||||
|
Drawable drawable = getDrawable();
|
||||||
|
canvas.save();
|
||||||
|
Paint.FontMetricsInt fmPaint = paint.getFontMetricsInt();
|
||||||
|
int fontHeight = fmPaint.descent - fmPaint.ascent;
|
||||||
|
int centerY = y + fmPaint.descent - fontHeight / 2;
|
||||||
|
int transY = centerY - (drawable.getBounds().bottom - drawable.getBounds().top) / 2;
|
||||||
|
canvas.translate(x, transY);
|
||||||
|
drawable.draw(canvas);
|
||||||
|
canvas.restore();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
package io.noties.markwon.emoji.ext;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class EmojiCode {
|
||||||
|
|
||||||
|
private String unicode;
|
||||||
|
private String unicode_alternates;
|
||||||
|
private String name;
|
||||||
|
private String shortname;
|
||||||
|
private String category;
|
||||||
|
private String emoji_order;
|
||||||
|
private List<Object> aliases;
|
||||||
|
private List<Object> aliases_ascii;
|
||||||
|
private List<String> keywords;
|
||||||
|
|
||||||
|
public enum EMOJI_SIZE{
|
||||||
|
SMALL, MEDIDUM, LARGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getImageName(){
|
||||||
|
String code = unicode.replace("-", "_");
|
||||||
|
code = "tw_" + code;
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUnicode() {
|
||||||
|
return unicode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUnicode_alternates() {
|
||||||
|
return unicode_alternates;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getShortname() {
|
||||||
|
return shortname;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCategory() {
|
||||||
|
return category;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmoji_order() {
|
||||||
|
return emoji_order;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Object> getAliases() {
|
||||||
|
return aliases;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Object> getAliases_ascii() {
|
||||||
|
return aliases_ascii;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getKeywords() {
|
||||||
|
return keywords;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package io.noties.markwon.emoji.ext;
|
||||||
|
|
||||||
|
import org.commonmark.node.CustomNode;
|
||||||
|
|
||||||
|
@SuppressWarnings("WeakerAccess")
|
||||||
|
public class EmojiGroupNode extends CustomNode {
|
||||||
|
|
||||||
|
}
|
37
markwon-emoji/src/main/java/io/noties/markwon/emoji/ext/EmojiNode.java
Executable file
@ -0,0 +1,37 @@
|
|||||||
|
package io.noties.markwon.emoji.ext;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import org.commonmark.node.CustomNode;
|
||||||
|
import org.commonmark.node.Delimited;
|
||||||
|
|
||||||
|
@SuppressWarnings("WeakerAccess")
|
||||||
|
public class EmojiNode extends CustomNode implements Delimited {
|
||||||
|
|
||||||
|
public static final char DELIMITER = ':';
|
||||||
|
|
||||||
|
public static final String DELIMITER_STRING = "" + DELIMITER;
|
||||||
|
|
||||||
|
|
||||||
|
private final String colonCode;
|
||||||
|
|
||||||
|
|
||||||
|
public EmojiNode(@NonNull String colonCode) {
|
||||||
|
this.colonCode = colonCode;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public String getColonCode() {
|
||||||
|
return colonCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getOpeningDelimiter() {
|
||||||
|
return DELIMITER_STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getClosingDelimiter() {
|
||||||
|
return DELIMITER_STRING;
|
||||||
|
}
|
||||||
|
}
|
53
markwon-emoji/src/main/java/io/noties/markwon/emoji/ext/EmojiPlugin.java
Executable file
@ -0,0 +1,53 @@
|
|||||||
|
package io.noties.markwon.emoji.ext;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import org.commonmark.parser.Parser;
|
||||||
|
|
||||||
|
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||||
|
import io.noties.markwon.MarkwonVisitor;
|
||||||
|
|
||||||
|
public class EmojiPlugin extends AbstractMarkwonPlugin {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static EmojiPlugin create(@NonNull EmojiSpanProvider emojiSpanProvider) {
|
||||||
|
return new EmojiPlugin(emojiSpanProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final EmojiSpanProvider emojiSpanProvider;
|
||||||
|
|
||||||
|
EmojiPlugin(@NonNull EmojiSpanProvider emojiSpanProvider) {
|
||||||
|
this.emojiSpanProvider = emojiSpanProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configureParser(@NonNull Parser.Builder builder) {
|
||||||
|
builder.customDelimiterProcessor(EmojiProcessor.create());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) {
|
||||||
|
builder.on(EmojiNode.class, new MarkwonVisitor.NodeVisitor<EmojiNode>() {
|
||||||
|
@Override
|
||||||
|
public void visit(@NonNull MarkwonVisitor visitor, @NonNull EmojiNode emojiNode) {
|
||||||
|
|
||||||
|
final String colonCode = emojiNode.getColonCode();
|
||||||
|
|
||||||
|
if (!TextUtils.isEmpty(colonCode)) {
|
||||||
|
|
||||||
|
final int length = visitor.length();
|
||||||
|
visitor.builder().append(colonCode);
|
||||||
|
visitor.setSpans(length, emojiSpanProvider.provide(colonCode));
|
||||||
|
visitor.builder().append(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public String processMarkdown(@NonNull String markdown) {
|
||||||
|
return EmojiProcessor.prepare(markdown);
|
||||||
|
}
|
||||||
|
}
|
158
markwon-emoji/src/main/java/io/noties/markwon/emoji/ext/EmojiProcessor.java
Executable file
@ -0,0 +1,158 @@
|
|||||||
|
package io.noties.markwon.emoji.ext;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import org.commonmark.node.Node;
|
||||||
|
import org.commonmark.node.Text;
|
||||||
|
import org.commonmark.parser.delimiter.DelimiterProcessor;
|
||||||
|
import org.commonmark.parser.delimiter.DelimiterRun;
|
||||||
|
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
@SuppressWarnings("WeakerAccess")
|
||||||
|
public class EmojiProcessor implements DelimiterProcessor {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static EmojiProcessor create() {
|
||||||
|
return new EmojiProcessor();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ic-home-black-24
|
||||||
|
private static final Pattern PATTERN = Pattern.compile("[a-z]{2,50}|[a-z]{2,50}[_][a-z]{2,50}|[a-z]{2,50}[_][a-z]{2,50}[_][a-z]{2,50}]");
|
||||||
|
|
||||||
|
private static final String TO_FIND = EmojiNode.DELIMITER_STRING;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should be used when input string does not wrap icon definition with `@` from both ends.
|
||||||
|
* So, `@ic-home-white-24` would become `@ic-home-white-24@`. This way parsing is easier
|
||||||
|
* and more predictable (cannot specify multiple ending delimiters, as we would require them:
|
||||||
|
* space, newline, end of a document, and a lot of more)
|
||||||
|
*
|
||||||
|
* @param input to process
|
||||||
|
* @return processed string
|
||||||
|
* @see #prepare(StringBuilder)
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public static String prepare(@NonNull String input) {
|
||||||
|
final StringBuilder builder = new StringBuilder(input);
|
||||||
|
prepare(builder);
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void prepare(@NonNull StringBuilder builder) {
|
||||||
|
|
||||||
|
// int start = builder.indexOf(TO_FIND);
|
||||||
|
// int end;
|
||||||
|
//
|
||||||
|
// while (start > -1) {
|
||||||
|
//
|
||||||
|
// end = iconDefinitionEnd(start + TO_FIND.length(), builder);
|
||||||
|
//
|
||||||
|
// // if we match our pattern, append `@` else ignore
|
||||||
|
// if (iconDefinitionValid(builder.subSequence(start + 1, end))) {
|
||||||
|
// builder.insert(end, '@');
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // move to next
|
||||||
|
// start = builder.indexOf(TO_FIND, end);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public char getOpeningCharacter() {
|
||||||
|
return EmojiNode.DELIMITER;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public char getClosingCharacter() {
|
||||||
|
return EmojiNode.DELIMITER;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMinLength() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDelimiterUse(DelimiterRun opener, DelimiterRun closer) {
|
||||||
|
return opener.length() >= 1 && closer.length() >= 1 ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(Text opener, Text closer, int delimiterUse) {
|
||||||
|
|
||||||
|
final EmojiGroupNode emojiGroupNode = new EmojiGroupNode();
|
||||||
|
|
||||||
|
final Node next = opener.getNext();
|
||||||
|
|
||||||
|
boolean handled = false;
|
||||||
|
|
||||||
|
// process only if we have exactly one Text node
|
||||||
|
if (next instanceof Text && next.getNext() == closer) {
|
||||||
|
|
||||||
|
final String text = ((Text) next).getLiteral();
|
||||||
|
|
||||||
|
if (!TextUtils.isEmpty(text)) {
|
||||||
|
|
||||||
|
// attempt to match
|
||||||
|
final Matcher matcher = PATTERN.matcher(text);
|
||||||
|
if (matcher.matches()) {
|
||||||
|
final EmojiNode emojiNode = new EmojiNode(
|
||||||
|
text
|
||||||
|
);
|
||||||
|
emojiGroupNode.appendChild(emojiNode);
|
||||||
|
next.unlink();
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!handled) {
|
||||||
|
|
||||||
|
// restore delimiters if we didn't match
|
||||||
|
|
||||||
|
emojiGroupNode.appendChild(new Text(EmojiNode.DELIMITER_STRING));
|
||||||
|
|
||||||
|
Node node;
|
||||||
|
for (Node tmp = opener.getNext(); tmp != null && tmp != closer; tmp = node) {
|
||||||
|
node = tmp.getNext();
|
||||||
|
// append a child anyway
|
||||||
|
emojiGroupNode.appendChild(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
emojiGroupNode.appendChild(new Text(EmojiNode.DELIMITER_STRING));
|
||||||
|
}
|
||||||
|
|
||||||
|
opener.insertBefore(emojiGroupNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int iconDefinitionEnd(int index, @NonNull StringBuilder builder) {
|
||||||
|
|
||||||
|
// all spaces, new lines, non-words or digits,
|
||||||
|
|
||||||
|
char c;
|
||||||
|
|
||||||
|
int end = -1;
|
||||||
|
for (int i = index; i < builder.length(); i++) {
|
||||||
|
c = builder.charAt(i);
|
||||||
|
if (Character.isWhitespace(c)
|
||||||
|
|| !(Character.isLetterOrDigit(c) || c == '-' || c == '_')) {
|
||||||
|
end = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (end == -1) {
|
||||||
|
end = builder.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean iconDefinitionValid(@NonNull CharSequence cs) {
|
||||||
|
final Matcher matcher = PATTERN.matcher(cs);
|
||||||
|
return matcher.matches();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,91 @@
|
|||||||
|
package io.noties.markwon.emoji.ext;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@SuppressWarnings("WeakerAccess")
|
||||||
|
public abstract class EmojiSpanProvider {
|
||||||
|
|
||||||
|
@SuppressWarnings("SameParameterValue")
|
||||||
|
@NonNull
|
||||||
|
public static EmojiSpanProvider create(@NonNull Context context, float textSize) {
|
||||||
|
return new Impl(context, textSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public abstract Object provide(@NonNull String text);
|
||||||
|
|
||||||
|
|
||||||
|
private static class Impl extends EmojiSpanProvider {
|
||||||
|
|
||||||
|
private final Context context;
|
||||||
|
private float textSize;
|
||||||
|
private Map<String, EmojiCode> emojiMap;
|
||||||
|
Impl(@NonNull Context context, float textSize) {
|
||||||
|
this.context = context;
|
||||||
|
this.textSize = textSize;
|
||||||
|
this.emojiMap = loadEmojiMapFromAssets();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, EmojiCode> loadEmojiMapFromAssets(){
|
||||||
|
try{
|
||||||
|
InputStream is = this.context.getAssets().open("emoji.json");
|
||||||
|
int size = is.available();
|
||||||
|
byte[] buffer = new byte[size];
|
||||||
|
is.read(buffer);
|
||||||
|
is.close();
|
||||||
|
String jsonString = new String(buffer, "UTF-8");
|
||||||
|
Gson gson = new Gson();
|
||||||
|
Type mapType = new TypeToken<Map<String, EmojiCode>>(){}.getType();
|
||||||
|
Map<String, EmojiCode> map = gson.fromJson(jsonString, mapType);
|
||||||
|
return map;
|
||||||
|
}catch (IOException e){
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Object provide(@NonNull String colonCode) {
|
||||||
|
return new CenterSpan(getDrawable(colonCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private Drawable getDrawable(String colonCode) {
|
||||||
|
EmojiCode emojiCode = emojiMap.get(colonCode);
|
||||||
|
int drawbleId = -1;
|
||||||
|
if (emojiCode != null){
|
||||||
|
String imageName = emojiCode.getImageName();
|
||||||
|
try{
|
||||||
|
drawbleId = context.getResources().getIdentifier(imageName, "drawable", context.getPackageName());
|
||||||
|
}catch (Exception e){
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Drawable emojiDrawable;
|
||||||
|
if (drawbleId != -1) {
|
||||||
|
emojiDrawable = context.getResources().getDrawable(drawbleId);
|
||||||
|
} else {
|
||||||
|
emojiDrawable = context.getResources().getDrawable(R.drawable.tw_1f30d);
|
||||||
|
}
|
||||||
|
|
||||||
|
int emojiHeight = emojiDrawable.getIntrinsicHeight();
|
||||||
|
int emojiWidth = emojiDrawable.getIntrinsicWidth();
|
||||||
|
int requiredWidth = emojiWidth * (int)textSize / emojiHeight;
|
||||||
|
emojiDrawable.setBounds(0, 0, requiredWidth, (int) textSize);
|
||||||
|
return emojiDrawable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
markwon-emoji/src/main/res/drawable/tw_1f004.png
Executable file
After Width: | Height: | Size: 551 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f0cf.png
Executable file
After Width: | Height: | Size: 923 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f170.png
Executable file
After Width: | Height: | Size: 557 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f171.png
Executable file
After Width: | Height: | Size: 458 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f17e.png
Executable file
After Width: | Height: | Size: 562 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f17f.png
Executable file
After Width: | Height: | Size: 403 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f18e.png
Executable file
After Width: | Height: | Size: 682 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f191.png
Executable file
After Width: | Height: | Size: 561 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f192.png
Executable file
After Width: | Height: | Size: 603 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f193.png
Executable file
After Width: | Height: | Size: 517 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f194.png
Executable file
After Width: | Height: | Size: 495 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f195.png
Executable file
After Width: | Height: | Size: 668 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f196.png
Executable file
After Width: | Height: | Size: 670 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f197.png
Executable file
After Width: | Height: | Size: 640 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f198.png
Executable file
After Width: | Height: | Size: 722 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f199.png
Executable file
After Width: | Height: | Size: 553 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f19a.png
Executable file
After Width: | Height: | Size: 747 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e6.png
Executable file
After Width: | Height: | Size: 559 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e6_1f1e8.png
Executable file
After Width: | Height: | Size: 1.0 KiB |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e6_1f1e9.png
Executable file
After Width: | Height: | Size: 697 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e6_1f1ea.png
Executable file
After Width: | Height: | Size: 287 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e6_1f1eb.png
Executable file
After Width: | Height: | Size: 1.1 KiB |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e6_1f1ec.png
Executable file
After Width: | Height: | Size: 849 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e6_1f1ee.png
Executable file
After Width: | Height: | Size: 989 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e6_1f1f1.png
Executable file
After Width: | Height: | Size: 662 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e6_1f1f2.png
Executable file
After Width: | Height: | Size: 245 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e6_1f1f4.png
Executable file
After Width: | Height: | Size: 723 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e6_1f1f6.png
Executable file
After Width: | Height: | Size: 481 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e6_1f1f7.png
Executable file
After Width: | Height: | Size: 453 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e6_1f1f8.png
Executable file
After Width: | Height: | Size: 847 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e6_1f1f9.png
Executable file
After Width: | Height: | Size: 205 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e6_1f1fa.png
Executable file
After Width: | Height: | Size: 835 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e6_1f1fc.png
Executable file
After Width: | Height: | Size: 387 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e6_1f1fd.png
Executable file
After Width: | Height: | Size: 230 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e6_1f1ff.png
Executable file
After Width: | Height: | Size: 402 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e7.png
Executable file
After Width: | Height: | Size: 459 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e7_1f1e6.png
Executable file
After Width: | Height: | Size: 652 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e7_1f1e7.png
Executable file
After Width: | Height: | Size: 406 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e7_1f1e9.png
Executable file
After Width: | Height: | Size: 336 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e7_1f1ea.png
Executable file
After Width: | Height: | Size: 233 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e7_1f1eb.png
Executable file
After Width: | Height: | Size: 390 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e7_1f1ec.png
Executable file
After Width: | Height: | Size: 244 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e7_1f1ed.png
Executable file
After Width: | Height: | Size: 411 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e7_1f1ee.png
Executable file
After Width: | Height: | Size: 940 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e7_1f1ef.png
Executable file
After Width: | Height: | Size: 279 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e7_1f1f1.png
Executable file
After Width: | Height: | Size: 978 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e7_1f1f2.png
Executable file
After Width: | Height: | Size: 919 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e7_1f1f3.png
Executable file
After Width: | Height: | Size: 884 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e7_1f1f4.png
Executable file
After Width: | Height: | Size: 666 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e7_1f1f6.png
Executable file
After Width: | Height: | Size: 871 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e7_1f1f7.png
Executable file
After Width: | Height: | Size: 805 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e7_1f1f8.png
Executable file
After Width: | Height: | Size: 419 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e7_1f1f9.png
Executable file
After Width: | Height: | Size: 1000 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e7_1f1fb.png
Executable file
After Width: | Height: | Size: 270 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e7_1f1fc.png
Executable file
After Width: | Height: | Size: 214 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e7_1f1fe.png
Executable file
After Width: | Height: | Size: 669 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e7_1f1ff.png
Executable file
After Width: | Height: | Size: 1.1 KiB |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e8.png
Executable file
After Width: | Height: | Size: 503 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e8_1f1e6.png
Executable file
After Width: | Height: | Size: 445 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e8_1f1e8.png
Executable file
After Width: | Height: | Size: 706 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e8_1f1e9.png
Executable file
After Width: | Height: | Size: 602 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e8_1f1eb.png
Executable file
After Width: | Height: | Size: 389 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e8_1f1ec.png
Executable file
After Width: | Height: | Size: 356 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e8_1f1ed.png
Executable file
After Width: | Height: | Size: 220 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e8_1f1ee.png
Executable file
After Width: | Height: | Size: 233 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e8_1f1f0.png
Executable file
After Width: | Height: | Size: 961 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e8_1f1f1.png
Executable file
After Width: | Height: | Size: 394 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e8_1f1f2.png
Executable file
After Width: | Height: | Size: 341 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e8_1f1f3.png
Executable file
After Width: | Height: | Size: 410 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e8_1f1f4.png
Executable file
After Width: | Height: | Size: 245 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e8_1f1f5.png
Executable file
After Width: | Height: | Size: 233 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e8_1f1f7.png
Executable file
After Width: | Height: | Size: 453 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e8_1f1fa.png
Executable file
After Width: | Height: | Size: 569 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e8_1f1fb.png
Executable file
After Width: | Height: | Size: 574 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e8_1f1fc.png
Executable file
After Width: | Height: | Size: 357 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e8_1f1fd.png
Executable file
After Width: | Height: | Size: 913 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e8_1f1fe.png
Executable file
After Width: | Height: | Size: 539 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e8_1f1ff.png
Executable file
After Width: | Height: | Size: 549 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e9.png
Executable file
After Width: | Height: | Size: 454 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e9_1f1ea.png
Executable file
After Width: | Height: | Size: 246 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e9_1f1ec.png
Executable file
After Width: | Height: | Size: 1.4 KiB |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e9_1f1ef.png
Executable file
After Width: | Height: | Size: 643 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e9_1f1f0.png
Executable file
After Width: | Height: | Size: 251 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e9_1f1f2.png
Executable file
After Width: | Height: | Size: 696 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e9_1f1f4.png
Executable file
After Width: | Height: | Size: 584 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1e9_1f1ff.png
Executable file
After Width: | Height: | Size: 524 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1ea.png
Executable file
After Width: | Height: | Size: 368 B |
BIN
markwon-emoji/src/main/res/drawable/tw_1f1ea_1f1e6.png
Executable file
After Width: | Height: | Size: 362 B |