diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiTextView.java b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiTextView.java
index 78cdd6aab..8449ea88d 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiTextView.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiTextView.java
@@ -24,7 +24,6 @@ import org.thoughtcrime.securesms.components.emoji.parsing.EmojiParser;
import org.thoughtcrime.securesms.components.mention.MentionAnnotation;
import org.thoughtcrime.securesms.components.mention.MentionRendererDelegate;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
-import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.libsignal.util.guava.Optional;
@@ -91,7 +90,8 @@ public class EmojiTextView extends AppCompatTextView {
super.onDraw(canvas);
}
- @Override public void setText(@Nullable CharSequence text, BufferType type) {
+ @Override
+ public void setText(@Nullable CharSequence text, BufferType type) {
EmojiParser.CandidateList candidates = isInEditMode() ? null : EmojiProvider.getCandidates(text);
if (scaleEmojis && candidates != null && candidates.allEmojis) {
@@ -118,23 +118,19 @@ public class EmojiTextView extends AppCompatTextView {
useSystemEmoji = useSystemEmoji();
if (useSystemEmoji || candidates == null || candidates.size() == 0) {
- super.setText(new SpannableStringBuilder(Optional.fromNullable(text).or("")).append(Optional.fromNullable(overflowText).or("")), BufferType.NORMAL);
-
- if (getEllipsize() == TextUtils.TruncateAt.END && maxLength > 0) {
- ellipsizeAnyTextForMaxLength();
- }
+ super.setText(new SpannableStringBuilder(Optional.fromNullable(text).or("")), BufferType.NORMAL);
} else {
CharSequence emojified = EmojiProvider.emojify(candidates, text, this);
- super.setText(new SpannableStringBuilder(emojified).append(Optional.fromNullable(overflowText).or("")), BufferType.SPANNABLE);
+ super.setText(new SpannableStringBuilder(emojified), BufferType.SPANNABLE);
+ }
- // Android fails to ellipsize spannable strings. (https://issuetracker.google.com/issues/36991688)
- // We ellipsize them ourselves by manually truncating the appropriate section.
- if (getEllipsize() == TextUtils.TruncateAt.END) {
- if (maxLength > 0) {
- ellipsizeAnyTextForMaxLength();
- } else {
- ellipsizeEmojiTextForMaxLines();
- }
+ // Android fails to ellipsize spannable strings. (https://issuetracker.google.com/issues/36991688)
+ // We ellipsize them ourselves by manually truncating the appropriate section.
+ if (getText() != null && getText().length() > 0 && getEllipsize() == TextUtils.TruncateAt.END) {
+ if (maxLength > 0) {
+ ellipsizeAnyTextForMaxLength();
+ } else if (getMaxLines() > 0) {
+ ellipsizeEmojiTextForMaxLines();
}
}
@@ -192,7 +188,8 @@ public class EmojiTextView extends AppCompatTextView {
if (lineCount > maxLines) {
int overflowStart = getLayout().getLineStart(maxLines - 1);
CharSequence overflow = getText().subSequence(overflowStart, getText().length());
- CharSequence ellipsized = TextUtils.ellipsize(overflow, getPaint(), getWidth(), TextUtils.TruncateAt.END);
+ float adjust = overflowText != null ? getPaint().measureText(overflowText, 0, overflowText.length()) : 0f;
+ CharSequence ellipsized = TextUtils.ellipsize(overflow, getPaint(), getWidth() - adjust, TextUtils.TruncateAt.END);
SpannableStringBuilder newContent = new SpannableStringBuilder();
newContent.append(getText().subSequence(0, overflowStart))
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationBannerView.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationBannerView.java
index 6f6ff36ef..7d4562160 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationBannerView.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationBannerView.java
@@ -19,6 +19,7 @@ import androidx.core.widget.ImageViewCompat;
import org.signal.core.util.concurrent.SignalExecutors;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.AvatarImageView;
+import org.thoughtcrime.securesms.components.emoji.EmojiTextView;
import org.thoughtcrime.securesms.contacts.avatars.FallbackContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto;
import org.thoughtcrime.securesms.database.DatabaseFactory;
@@ -31,7 +32,7 @@ public class ConversationBannerView extends ConstraintLayout {
private TextView contactTitle;
private TextView contactAbout;
private TextView contactSubtitle;
- private TextView contactDescription;
+ private EmojiTextView contactDescription;
private View tapToView;
public ConversationBannerView(Context context) {
@@ -91,6 +92,10 @@ public class ConversationBannerView extends ConstraintLayout {
contactDescription.setVisibility(TextUtils.isEmpty(description) ? GONE : VISIBLE);
}
+ public @NonNull EmojiTextView getDescription() {
+ return contactDescription;
+ }
+
public void showBackgroundBubble(boolean enabled) {
if (enabled) {
setBackgroundResource(R.drawable.wallpaper_bubble_background_12);
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java
index f8e25c7ab..a24ad2033 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java
@@ -541,13 +541,15 @@ public class ConversationFragment extends LoggingFragment {
} else {
conversationBanner.setLinkifyDescription(true);
boolean linkifyWebLinks = recipientInfo.getMessageRequestState() == MessageRequestState.NONE;
- conversationBanner.setDescription(GroupDescriptionUtil.style(context,
- recipientInfo.getGroupDescription(),
- linkifyWebLinks,
- () -> GroupDescriptionDialog.show(getChildFragmentManager(),
- recipient.getDisplayName(context),
- recipientInfo.getGroupDescription(),
- linkifyWebLinks)));
+ conversationBanner.showDescription();
+ GroupDescriptionUtil.setText(context,
+ conversationBanner.getDescription(),
+ recipientInfo.getGroupDescription(),
+ linkifyWebLinks,
+ () -> GroupDescriptionDialog.show(getChildFragmentManager(),
+ recipient.getDisplayName(context),
+ recipientInfo.getGroupDescription(),
+ linkifyWebLinks));
}
} else {
final String description;
diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/invitesandrequests/joining/GroupJoinBottomSheetDialogFragment.java b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/invitesandrequests/joining/GroupJoinBottomSheetDialogFragment.java
index e23ded8be..90df28c48 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/invitesandrequests/joining/GroupJoinBottomSheetDialogFragment.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/invitesandrequests/joining/GroupJoinBottomSheetDialogFragment.java
@@ -24,6 +24,7 @@ import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.components.AvatarImageView;
+import org.thoughtcrime.securesms.components.emoji.EmojiTextView;
import org.thoughtcrime.securesms.contacts.avatars.FallbackContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto;
import org.thoughtcrime.securesms.conversation.ConversationIntents;
@@ -46,7 +47,7 @@ public final class GroupJoinBottomSheetDialogFragment extends BottomSheetDialogF
private AvatarImageView avatar;
private TextView groupName;
private TextView groupDetails;
- private TextView groupDescription;
+ private EmojiTextView groupDescription;
private TextView groupJoinExplain;
private Button groupJoinButton;
private Button groupCancelButton;
@@ -158,10 +159,11 @@ public final class GroupJoinBottomSheetDialogFragment extends BottomSheetDialogF
private void updateGroupDescription(@NonNull String name, @NonNull String description) {
groupDescription.setVisibility(View.VISIBLE);
groupDescription.setMovementMethod(LinkMovementMethod.getInstance());
- groupDescription.setText(GroupDescriptionUtil.style(requireContext(),
- description,
- true,
- () -> GroupDescriptionDialog.show(getChildFragmentManager(), name, description, true)));
+ GroupDescriptionUtil.setText(requireContext(),
+ groupDescription,
+ description,
+ true,
+ () -> GroupDescriptionDialog.show(getChildFragmentManager(), name, description, true));
}
private static ExtendedGroupJoinStatus getGroupJoinStatus() {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/managegroup/ManageGroupFragment.java b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/managegroup/ManageGroupFragment.java
index 0c4cc6480..a4b018e01 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/managegroup/ManageGroupFragment.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/managegroup/ManageGroupFragment.java
@@ -458,15 +458,17 @@ public class ManageGroupFragment extends LoggingFragment {
if (TextUtils.isEmpty(description.getDescription())) {
if (FeatureFlags.groupsV2Description() && description.canEditDescription()) {
+ groupDescription.setOverflowText(null);
groupDescription.setText(R.string.ManageGroupActivity_add_group_description);
groupDescription.setOnClickListener(v -> startActivity(EditProfileActivity.getIntentForGroupProfile(requireActivity(), getGroupId())));
}
} else {
groupDescription.setOnClickListener(null);
- groupDescription.setText(GroupDescriptionUtil.style(requireContext(),
- description.getDescription(),
- description.shouldLinkifyWebLinks(),
- () -> GroupDescriptionDialog.show(getChildFragmentManager(), getGroupId(), null, description.shouldLinkifyWebLinks())));
+ GroupDescriptionUtil.setText(requireContext(),
+ groupDescription,
+ description.getDescription(),
+ description.shouldLinkifyWebLinks(),
+ () -> GroupDescriptionDialog.show(getChildFragmentManager(), getGroupId(), null, description.shouldLinkifyWebLinks()));
}
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/managegroup/dialogs/GroupDescriptionDialog.java b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/managegroup/dialogs/GroupDescriptionDialog.java
index a72fc16f8..5ec625181 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/managegroup/dialogs/GroupDescriptionDialog.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/managegroup/dialogs/GroupDescriptionDialog.java
@@ -16,6 +16,7 @@ import androidx.fragment.app.FragmentManager;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.thoughtcrime.securesms.R;
+import org.thoughtcrime.securesms.components.emoji.EmojiTextView;
import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.groups.LiveGroup;
import org.thoughtcrime.securesms.groups.ParcelableGroupId;
@@ -34,7 +35,7 @@ public final class GroupDescriptionDialog extends DialogFragment {
private static final String ARGUMENT_LINKIFY = "linkify";
private static final String DIALOG_TAG = "GroupDescriptionDialog";
- private TextView descriptionText;
+ private EmojiTextView descriptionText;
public static void show(@NonNull FragmentManager fragmentManager, @NonNull String title, @Nullable String description, boolean linkify) {
show(fragmentManager, null, title, description, linkify);
@@ -76,9 +77,9 @@ public final class GroupDescriptionDialog extends DialogFragment {
.create();
if (argumentDescription != null) {
- descriptionText.setText(GroupDescriptionUtil.style(requireContext(), argumentDescription, linkify, null));
+ GroupDescriptionUtil.setText(requireContext(), descriptionText, argumentDescription, linkify, null);
} else if (liveGroup != null) {
- liveGroup.getDescription().observe(this, d -> descriptionText.setText(GroupDescriptionUtil.style(requireContext(), d, linkify, null)));
+ liveGroup.getDescription().observe(this, d -> GroupDescriptionUtil.setText(requireContext(), descriptionText, d, linkify, null));
}
if (TextUtils.isEmpty(argumentTitle) && liveGroup != null) {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/v2/GroupDescriptionUtil.java b/app/src/main/java/org/thoughtcrime/securesms/groups/v2/GroupDescriptionUtil.java
index 74a182003..03a3b53e6 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/groups/v2/GroupDescriptionUtil.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/groups/v2/GroupDescriptionUtil.java
@@ -7,6 +7,7 @@ import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextPaint;
+import android.text.TextUtils;
import android.text.style.ClickableSpan;
import android.text.style.URLSpan;
import android.text.util.Linkify;
@@ -18,6 +19,7 @@ import androidx.annotation.Nullable;
import com.annimon.stream.Stream;
import org.thoughtcrime.securesms.R;
+import org.thoughtcrime.securesms.components.emoji.EmojiTextView;
import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil;
public final class GroupDescriptionUtil {
@@ -25,14 +27,14 @@ public final class GroupDescriptionUtil {
public static final int MAX_DESCRIPTION_LENGTH = 80;
/**
- * Style a group description.
+ * Set a group description.
*
- * @param description full description
- * @param linkify flag indicating if web urls should be linkified
- * @param moreClick Callback for when truncating and need to show more via another means. Required to enable truncating.
- * @return styled group description
+ * @param description full description
+ * @param emojiTextView Text view to update with description
+ * @param linkify flag indicating if web urls should be linkified
+ * @param moreClick Callback for when truncating and need to show more via another means. Required to enable truncating.
*/
- public static @NonNull Spannable style(@NonNull Context context, @NonNull String description, boolean linkify, @Nullable Runnable moreClick) {
+ public static void setText(@NonNull Context context, @NonNull EmojiTextView emojiTextView, @NonNull String description, boolean linkify, @Nullable Runnable moreClick) {
SpannableString descriptionSpannable = new SpannableString(description);
if (linkify) {
@@ -46,7 +48,7 @@ public final class GroupDescriptionUtil {
}
}
- if (moreClick != null && descriptionSpannable.length() > MAX_DESCRIPTION_LENGTH) {
+ if (moreClick != null) {
ClickableSpan style = new ClickableSpan() {
@Override
public void onClick(@NonNull View widget) {
@@ -59,11 +61,14 @@ public final class GroupDescriptionUtil {
}
};
- SpannableStringBuilder builder = new SpannableStringBuilder(descriptionSpannable.subSequence(0, MAX_DESCRIPTION_LENGTH)).append(context.getString(R.string.ManageGroupActivity_more));
- builder.setSpan(style, MAX_DESCRIPTION_LENGTH + 1, builder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- return builder;
+ emojiTextView.setEllipsize(TextUtils.TruncateAt.END);
+ emojiTextView.setMaxLines(2);
+
+ SpannableString overflowText = new SpannableString(context.getString(R.string.ManageGroupActivity_more));
+ overflowText.setSpan(style, 0, overflowText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ emojiTextView.setOverflowText(overflowText);
}
- return descriptionSpannable;
+ emojiTextView.setText(descriptionSpannable);
}
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/stickers/StickerManagementAdapter.java b/app/src/main/java/org/thoughtcrime/securesms/stickers/StickerManagementAdapter.java
index 6773910a8..4a1417f67 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/stickers/StickerManagementAdapter.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/stickers/StickerManagementAdapter.java
@@ -4,6 +4,7 @@ import android.content.Context;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
import android.text.style.ImageSpan;
import android.view.LayoutInflater;
import android.view.View;
@@ -261,16 +262,15 @@ final class StickerManagementAdapter extends SectionedRecyclerViewAdapterupgrade this group.
This is an insecure MMS Group. To chat privately, invite your contacts to Signal.
Invite now
- …more
+ more
Add group description…