Show member labels in quotes.

This commit is contained in:
jeffrey-signal
2026-02-11 15:52:38 -05:00
committed by Michelle Tang
parent e384a37fab
commit cb05608422
16 changed files with 279 additions and 95 deletions

View File

@@ -219,7 +219,7 @@ public class InputPanel extends ConstraintLayout
@NonNull SlideDeck attachments,
@NonNull QuoteModel.Type quoteType)
{
this.quoteView.setQuote(requestManager, id, author, body, false, attachments, null, quoteType, true);
this.quoteView.setQuote(requestManager, id, author, body, false, attachments, null, quoteType, true, null);
if (listener != null) {
this.quoteView.setOnClickListener(v -> listener.onQuoteClicked(id, author.getId()));
}

View File

@@ -22,9 +22,11 @@ import com.google.android.material.imageview.ShapeableImageView;
import com.google.android.material.shape.CornerFamily;
import com.google.android.material.shape.ShapeAppearanceModel;
import org.signal.core.util.DimensionUnit;
import org.signal.core.util.logging.Log;
import org.signal.core.ui.view.Stub;
import org.signal.core.util.DimensionUnit;
import org.signal.core.util.Util;
import org.signal.core.util.logging.Log;
import org.signal.glide.decryptableuri.DecryptableUri;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.components.emoji.EmojiImageView;
@@ -32,10 +34,11 @@ import org.thoughtcrime.securesms.components.emoji.EmojiTextView;
import org.thoughtcrime.securesms.components.mention.MentionAnnotation;
import org.thoughtcrime.securesms.components.quotes.QuoteViewColorTheme;
import org.thoughtcrime.securesms.conversation.MessageStyler;
import org.thoughtcrime.securesms.conversation.v2.items.SenderNameWithLabelView;
import org.thoughtcrime.securesms.database.model.Mention;
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList;
import org.thoughtcrime.securesms.fonts.SignalSymbols;
import org.signal.glide.decryptableuri.DecryptableUri;
import org.thoughtcrime.securesms.groups.memberlabel.MemberLabel;
import org.thoughtcrime.securesms.mms.QuoteModel;
import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.mms.SlideDeck;
@@ -45,7 +48,6 @@ import org.thoughtcrime.securesms.recipients.RecipientForeverObserver;
import org.thoughtcrime.securesms.stories.StoryTextPostModel;
import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.Projection;
import org.signal.core.util.Util;
import java.io.IOException;
import java.util.List;
@@ -81,28 +83,29 @@ public class QuoteView extends ConstraintLayout implements RecipientForeverObser
}
}
private TextView authorView;
private EmojiTextView bodyView;
private View quoteBarView;
private ShapeableImageView thumbnailView;
private Stub<View> attachmentVideoOVerlayStub;
private Stub<TextView> attachmentNameViewStub;
private Stub<ImageView> dismissStub;
private EmojiImageView missingStoryReaction;
private EmojiImageView storyReactionEmoji;
private SenderNameWithLabelView authorView;
private EmojiTextView bodyView;
private View quoteBarView;
private ShapeableImageView thumbnailView;
private Stub<View> attachmentVideoOVerlayStub;
private Stub<TextView> attachmentNameViewStub;
private Stub<ImageView> dismissStub;
private EmojiImageView missingStoryReaction;
private EmojiImageView storyReactionEmoji;
private long id;
private LiveRecipient author;
private CharSequence body;
private TextView mediaDescriptionText;
private Stub<TextView> missingLinkTextStub;
private SlideDeck attachments;
private MessageType messageType;
private int largeCornerRadius;
private int smallCornerRadius;
private CornerMask cornerMask;
private QuoteModel.Type quoteType;
private boolean isWallpaperEnabled;
private long id;
private LiveRecipient author;
private CharSequence body;
private TextView mediaDescriptionText;
private Stub<TextView> missingLinkTextStub;
private SlideDeck attachments;
private MessageType messageType;
private int largeCornerRadius;
private int smallCornerRadius;
private CornerMask cornerMask;
private QuoteModel.Type quoteType;
private boolean isWallpaperEnabled;
@Nullable private MemberLabel memberLabel;
private int thumbHeight;
private int thumbWidth;
@@ -181,13 +184,13 @@ public class QuoteView extends ConstraintLayout implements RecipientForeverObser
cornerMask.setTopLeftRadius(radius);
cornerMask.setTopRightRadius(radius);
} else if (isStoryReply()) {
thumbWidth = getResources().getDimensionPixelOffset(R.dimen.quote_story_thumb_width);
thumbWidth = getResources().getDimensionPixelOffset(R.dimen.quote_story_thumb_width);
thumbHeight = getResources().getDimensionPixelOffset(R.dimen.quote_story_thumb_height);
}
ViewGroup.LayoutParams params = thumbnailView.getLayoutParams();
params.height = thumbHeight;
params.width = thumbWidth;
params.width = thumbWidth;
thumbnailView.setLayoutParams(params);
dismissStub.setVisibility(messageType == MessageType.PREVIEW ? View.VISIBLE : View.GONE);
@@ -204,7 +207,8 @@ public class QuoteView extends ConstraintLayout implements RecipientForeverObser
@NonNull SlideDeck attachments,
@Nullable String storyReaction,
@NonNull QuoteModel.Type quoteType,
boolean composeMode)
boolean composeMode,
@Nullable MemberLabel memberLabel)
{
if (this.author != null) this.author.removeForeverObserver(this);
@@ -213,6 +217,7 @@ public class QuoteView extends ConstraintLayout implements RecipientForeverObser
this.body = body;
this.attachments = attachments;
this.quoteType = quoteType;
this.memberLabel = memberLabel;
this.author.observeForever(this);
@@ -267,18 +272,25 @@ public class QuoteView extends ConstraintLayout implements RecipientForeverObser
public void onRecipientChanged(@NonNull Recipient recipient) {
setQuoteAuthor(recipient);
}
public @NonNull Projection.Corners getCorners() {
return new Projection.Corners(cornerMask.getRadii());
}
private void setQuoteAuthor(@NonNull Recipient author) {
String name;
if (isStoryReply()) {
authorView.setText(author.isSelf() ? getContext().getString(R.string.QuoteView_your_story)
: getContext().getString(R.string.QuoteView_s_story, author.getDisplayName(getContext())));
name = author.isSelf() ? getContext().getString(R.string.QuoteView_your_story)
: getContext().getString(R.string.QuoteView_s_story, author.getDisplayName(getContext()));
} else {
authorView.setText(author.isSelf() ? getContext().getString(R.string.QuoteView_you)
: author.getDisplayName(getContext()));
name = author.isSelf() ? getContext().getString(R.string.QuoteView_you)
: author.getDisplayName(getContext());
}
QuoteViewColorTheme colorTheme = getColorTheme();
int foregroundColor = colorTheme.getForegroundColor(getContext());
authorView.setSender(name, foregroundColor);
authorView.setLabel(memberLabel, foregroundColor, colorTheme.getLabelBackgroundColor(getContext()));
}
private boolean isStoryReply() {
@@ -327,12 +339,12 @@ public class QuoteView extends ConstraintLayout implements RecipientForeverObser
bodyView.setText("");
}
} else if (quoteType == QuoteModel.Type.POLL) {
CharSequence glyph = SignalSymbols.getSpannedString(getContext(), SignalSymbols.Weight.REGULAR, SignalSymbols.Glyph.POLL, -1);
CharSequence glyph = SignalSymbols.getSpannedString(getContext(), SignalSymbols.Weight.REGULAR, SignalSymbols.Glyph.POLL, -1);
// TODO(michelle): Update with RTL poll icon
SpannableStringBuilder builder = new SpannableStringBuilder()
.append(glyph)
.append(" ")
.append(body);
.append(glyph)
.append(" ")
.append(body);
bodyView.setText(body == null ? "" : builder);
} else {
bodyView.setText(body == null ? "" : body);
@@ -396,10 +408,10 @@ public class QuoteView extends ConstraintLayout implements RecipientForeverObser
attachmentNameViewStub.setVisibility(GONE);
thumbnailView.setVisibility(VISIBLE);
requestManager.load(model)
.centerCrop()
.override(thumbWidth, thumbHeight)
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.into(thumbnailView);
.centerCrop()
.override(thumbWidth, thumbHeight)
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.into(thumbnailView);
return;
}
@@ -414,10 +426,10 @@ public class QuoteView extends ConstraintLayout implements RecipientForeverObser
attachmentNameViewStub.setVisibility(GONE);
thumbnailView.setVisibility(VISIBLE);
requestManager.load(R.drawable.ic_gift_thumbnail)
.centerCrop()
.override(thumbWidth, thumbHeight)
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.into(thumbnailView);
.centerCrop()
.override(thumbWidth, thumbHeight)
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.into(thumbnailView);
return;
}
@@ -536,14 +548,14 @@ public class QuoteView extends ConstraintLayout implements RecipientForeverObser
}
private void applyColorTheme() {
boolean isOutgoing = messageType != MessageType.INCOMING && messageType != MessageType.STORY_REPLY_INCOMING;
boolean isPreview = messageType == MessageType.PREVIEW || messageType == MessageType.STORY_REPLY_PREVIEW;
QuoteViewColorTheme quoteViewColorTheme = QuoteViewColorTheme.resolveTheme(isOutgoing, isPreview, isWallpaperEnabled);
QuoteViewColorTheme quoteViewColorTheme = getColorTheme();
quoteBarView.setBackgroundColor(quoteViewColorTheme.getBarColor(getContext()));
setBackgroundColor(quoteViewColorTheme.getBackgroundColor(getContext()));
authorView.setTextColor(quoteViewColorTheme.getForegroundColor(getContext()));
authorView.updateColors(
quoteViewColorTheme.getForegroundColor(getContext()),
quoteViewColorTheme.getLabelBackgroundColor(getContext())
);
bodyView.setTextColor(quoteViewColorTheme.getForegroundColor(getContext()));
if (attachmentNameViewStub.resolved()) {
@@ -556,4 +568,10 @@ public class QuoteView extends ConstraintLayout implements RecipientForeverObser
missingLinkTextStub.get().setBackgroundColor(quoteViewColorTheme.getBackgroundColor(getContext()));
}
}
private @NonNull QuoteViewColorTheme getColorTheme() {
boolean isOutgoing = messageType != MessageType.INCOMING && messageType != MessageType.STORY_REPLY_INCOMING;
boolean isPreview = messageType == MessageType.PREVIEW || messageType == MessageType.STORY_REPLY_PREVIEW;
return QuoteViewColorTheme.resolveTheme(isOutgoing, isPreview, isWallpaperEnabled);
}
}

View File

@@ -1,39 +1,46 @@
package org.thoughtcrime.securesms.components.quotes
import android.content.Context
import androidx.annotation.ColorRes
import androidx.core.content.ContextCompat
import org.thoughtcrime.securesms.R
enum class QuoteViewColorTheme(
private val backgroundColorRes: Int,
private val barColorRes: Int,
private val foregroundColorRes: Int
@param:ColorRes private val backgroundColorRes: Int,
@param:ColorRes private val barColorRes: Int,
@param:ColorRes private val foregroundColorRes: Int,
@param:ColorRes private val labelBackgroundColorRes: Int
) {
INCOMING_WALLPAPER(
R.color.quote_view_background_incoming_wallpaper,
R.color.quote_view_bar_incoming_wallpaper,
R.color.quote_view_foreground_incoming_wallpaper
R.color.quote_view_foreground_incoming_wallpaper,
R.color.quote_view_label_background_incoming_wallpaper
),
INCOMING_NORMAL(
R.color.quote_view_background_incoming_normal,
R.color.quote_view_bar_incoming_normal,
R.color.quote_view_foreground_incoming_normal
R.color.quote_view_foreground_incoming_normal,
R.color.quote_view_label_background_incoming_normal
),
OUTGOING_WALLPAPER(
R.color.quote_view_background_outgoing_wallpaper,
R.color.quote_view_bar_outgoing_wallpaper,
R.color.quote_view_foreground_outgoing_wallpaper
R.color.quote_view_foreground_outgoing_wallpaper,
R.color.quote_view_label_background_outgoing_wallpaper
),
OUTGOING_NORMAL(
R.color.quote_view_background_outgoing_normal,
R.color.quote_view_bar_outgoing_normal,
R.color.quote_view_foreground_outgoing_normal
R.color.quote_view_foreground_outgoing_normal,
R.color.quote_view_label_background_outgoing_normal
);
fun getBackgroundColor(context: Context) = ContextCompat.getColor(context, backgroundColorRes)
fun getBarColor(context: Context) = ContextCompat.getColor(context, barColorRes)
fun getForegroundColor(context: Context) = ContextCompat.getColor(context, foregroundColorRes)
fun getLabelBackgroundColor(context: Context) = ContextCompat.getColor(context, labelBackgroundColorRes)
companion object {
@JvmStatic

View File

@@ -125,7 +125,7 @@ object RecipientPreference {
style = MemberLabelPillView.Style(
horizontalPadding = 8.dp,
verticalPadding = 2.dp,
textStyle = { MaterialTheme.typography.bodySmall }
textStyle = { MaterialTheme.typography.labelSmall }
)
setLabel(styledLabel.label, styledLabel.tintColor)
visible = true