From b17cba621e882d5ed1d8c3d5b7acc64e62349ca2 Mon Sep 17 00:00:00 2001 From: Mateo Hernandez Date: Tue, 25 Apr 2017 19:09:35 -0500 Subject: [PATCH] Show emoji-only messages larger Closes #6531 // FREEBIE --- res/layout/conversation_item_received.xml | 3 +- res/layout/conversation_item_sent.xml | 3 +- res/values/attrs.xml | 4 +++ .../components/emoji/EmojiProvider.java | 14 ++++++-- .../components/emoji/EmojiTextView.java | 32 ++++++++++++++++++- .../components/emoji/parsing/EmojiParser.java | 30 +++++++++++++++-- 6 files changed, 77 insertions(+), 9 deletions(-) diff --git a/res/layout/conversation_item_received.xml b/res/layout/conversation_item_received.xml index fa357bf2ce..5169b4eb01 100644 --- a/res/layout/conversation_item_received.xml +++ b/res/layout/conversation_item_received.xml @@ -75,7 +75,8 @@ android:textAppearance="?android:attr/textAppearanceSmall" android:textColor="?conversation_item_received_text_primary_color" android:textColorLink="?conversation_item_received_text_primary_color" - android:textSize="@dimen/conversation_item_body_text_size" /> + android:textSize="@dimen/conversation_item_body_text_size" + app:scaleEmojis="true" /> + app:scaleEmojis="true" + tools:text="Mango pickle lorem ipsum"/> + + + + diff --git a/src/org/thoughtcrime/securesms/components/emoji/EmojiProvider.java b/src/org/thoughtcrime/securesms/components/emoji/EmojiProvider.java index a3e194e55b..b6f7d3d4ff 100644 --- a/src/org/thoughtcrime/securesms/components/emoji/EmojiProvider.java +++ b/src/org/thoughtcrime/securesms/components/emoji/EmojiProvider.java @@ -26,7 +26,6 @@ import org.thoughtcrime.securesms.components.emoji.parsing.EmojiTree; import org.thoughtcrime.securesms.util.FutureTaskListener; import org.thoughtcrime.securesms.util.Util; -import java.util.List; import java.util.concurrent.ExecutionException; class EmojiProvider { @@ -71,10 +70,19 @@ class EmojiProvider { } } - @Nullable Spannable emojify(@Nullable CharSequence text, @NonNull TextView tv) { + @Nullable EmojiParser.CandidateList getCandidates(@Nullable CharSequence text) { if (text == null) return null; + return new EmojiParser(emojiTree).findCandidates(text); + } + + @Nullable Spannable emojify(@Nullable CharSequence text, @NonNull TextView tv) { + return emojify(getCandidates(text), text, tv); + } - List matches = new EmojiParser(emojiTree).findCandidates(text); + @Nullable Spannable emojify(@Nullable EmojiParser.CandidateList matches, + @Nullable CharSequence text, + @NonNull TextView tv) { + if (matches == null || text == null) return null; SpannableStringBuilder builder = new SpannableStringBuilder(text); for (EmojiParser.Candidate candidate : matches) { diff --git a/src/org/thoughtcrime/securesms/components/emoji/EmojiTextView.java b/src/org/thoughtcrime/securesms/components/emoji/EmojiTextView.java index 31c2972206..0cfb1bf53b 100644 --- a/src/org/thoughtcrime/securesms/components/emoji/EmojiTextView.java +++ b/src/org/thoughtcrime/securesms/components/emoji/EmojiTextView.java @@ -1,6 +1,7 @@ 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; @@ -9,12 +10,18 @@ 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 final float originalFontSize; + private CharSequence source; private boolean needsEllipsizing; @@ -28,15 +35,38 @@ public class EmojiTextView extends AppCompatTextView { 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; + setTextSize(TypedValue.COMPLEX_UNIT_PX, getTextSize() * scale); + } else if (scaleEmojis) { + setTextSize(TypedValue.COMPLEX_UNIT_PX, originalFontSize); + } + if (useSystemEmoji()) { super.setText(text, type); return; } - source = EmojiProvider.getInstance(getContext()).emojify(text, this); + source = EmojiProvider.getInstance(getContext()).emojify(candidates, text, this); setTextEllipsized(source); } diff --git a/src/org/thoughtcrime/securesms/components/emoji/parsing/EmojiParser.java b/src/org/thoughtcrime/securesms/components/emoji/parsing/EmojiParser.java index 95a92b0b2d..0fec9806e7 100644 --- a/src/org/thoughtcrime/securesms/components/emoji/parsing/EmojiParser.java +++ b/src/org/thoughtcrime/securesms/components/emoji/parsing/EmojiParser.java @@ -24,6 +24,7 @@ package org.thoughtcrime.securesms.components.emoji.parsing; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -38,10 +39,12 @@ public class EmojiParser { this.emojiTree = emojiTree; } - public @NonNull List findCandidates(@Nullable CharSequence text) { + public @NonNull CandidateList findCandidates(@Nullable CharSequence text) { List results = new LinkedList<>(); - if (text == null) return results; + if (text == null) return new CandidateList(results, false); + + boolean allEmojis = text.length() > 0; for (int i = 0; i < text.length(); i++) { int emojiEnd = getEmojiEndPos(text, i); @@ -58,10 +61,12 @@ public class EmojiParser { results.add(new Candidate(i, emojiEnd, drawInfo)); i = emojiEnd - 1; + } else { + allEmojis = false; } } - return results; + return new CandidateList(results, allEmojis); } private int getEmojiEndPos(CharSequence text, int startPos) { @@ -105,4 +110,23 @@ public class EmojiParser { } } + public class CandidateList implements Iterable { + public final List list; + public final boolean allEmojis; + + public CandidateList(List candidates, boolean allEmojis) { + this.list = candidates; + this.allEmojis = allEmojis; + } + + public int size() { + return list.size(); + } + + @Override + public Iterator iterator() { + return list.iterator(); + } + } + }