diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/InputPanel.java b/app/src/main/java/org/thoughtcrime/securesms/components/InputPanel.java index 3de523f655..08df078bc3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/InputPanel.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/InputPanel.java @@ -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())); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/QuoteView.java b/app/src/main/java/org/thoughtcrime/securesms/components/QuoteView.java index 825c8b6ea3..0a17f59ec8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/QuoteView.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/QuoteView.java @@ -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 attachmentVideoOVerlayStub; - private Stub attachmentNameViewStub; - private Stub dismissStub; - private EmojiImageView missingStoryReaction; - private EmojiImageView storyReactionEmoji; + private SenderNameWithLabelView authorView; + private EmojiTextView bodyView; + private View quoteBarView; + private ShapeableImageView thumbnailView; + private Stub attachmentVideoOVerlayStub; + private Stub attachmentNameViewStub; + private Stub dismissStub; + private EmojiImageView missingStoryReaction; + private EmojiImageView storyReactionEmoji; - private long id; - private LiveRecipient author; - private CharSequence body; - private TextView mediaDescriptionText; - private Stub 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 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); + } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/quotes/QuoteViewColorTheme.kt b/app/src/main/java/org/thoughtcrime/securesms/components/quotes/QuoteViewColorTheme.kt index fd9bc462fb..63e92e2e81 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/quotes/QuoteViewColorTheme.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/quotes/QuoteViewColorTheme.kt @@ -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 diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/preferences/RecipientPreference.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/preferences/RecipientPreference.kt index ed35288b23..61404bce91 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/preferences/RecipientPreference.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/preferences/RecipientPreference.kt @@ -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 diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java index c38b1bab7c..2b3d7a2865 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java @@ -1725,7 +1725,8 @@ public final class ConversationItem extends RelativeLayout implements BindableCo quote.getAttachment(), isStoryReaction(current) ? current.getBody() : null, quote.getQuoteType(), - false); + false, + conversationMessage.getQuoteMemberLabel()); quoteView.setWallpaperEnabled(hasWallpaper); quoteView.setVisibility(View.VISIBLE); diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationMessage.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationMessage.java index a6efd3374b..faa64b0220 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationMessage.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationMessage.java @@ -50,6 +50,7 @@ public class ConversationMessage { @Nullable private final MessageRecord originalMessage; @NonNull private final ComputedProperties computedProperties; @Nullable private final MemberLabel memberLabel; + @Nullable private final MemberLabel quoteMemberLabel; private ConversationMessage(@NonNull MessageRecord messageRecord, @Nullable CharSequence body, @@ -59,7 +60,8 @@ public class ConversationMessage { @NonNull Recipient threadRecipient, @Nullable MessageRecord originalMessage, @NonNull ComputedProperties computedProperties, - @Nullable MemberLabel memberLabel) + @Nullable MemberLabel memberLabel, + @Nullable MemberLabel quoteMemberLabel) { this.messageRecord = messageRecord; this.hasBeenQuoted = hasBeenQuoted; @@ -69,6 +71,7 @@ public class ConversationMessage { this.originalMessage = originalMessage; this.computedProperties = computedProperties; this.memberLabel = memberLabel; + this.quoteMemberLabel = quoteMemberLabel; if (body != null) { this.body = SpannableString.valueOf(body); @@ -109,6 +112,10 @@ public class ConversationMessage { return memberLabel; } + public @Nullable MemberLabel getQuoteMemberLabel() { + return quoteMemberLabel; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -242,8 +249,9 @@ public class ConversationMessage { } } - FormattedDate formattedDate = getFormattedDate(context, messageRecord); - MemberLabel memberLabel = getMemberLabel(messageRecord, threadRecipient); + FormattedDate formattedDate = getFormattedDate(context, messageRecord); + MemberLabel memberLabel = getMemberLabel(messageRecord, threadRecipient); + MemberLabel quoteMemberLabel = getQuoteMemberLabel(messageRecord, threadRecipient); return new ConversationMessage(messageRecord, styledAndMentionBody != null ? styledAndMentionBody : mentionsUpdate != null ? mentionsUpdate.getBody() : body, @@ -253,7 +261,8 @@ public class ConversationMessage { threadRecipient, originalMessage, new ComputedProperties(formattedDate), - memberLabel); + memberLabel, + quoteMemberLabel); } /** @@ -298,5 +307,15 @@ public class ConversationMessage { } return MemberLabelRepository.getInstance().getLabelJava(threadRecipient.requireGroupId().requireV2(), messageRecord.getFromRecipient()); } + + @WorkerThread + private static @Nullable MemberLabel getQuoteMemberLabel(@NonNull MessageRecord messageRecord, @NonNull Recipient threadRecipient) { + if (!threadRecipient.isPushV2Group() || !(messageRecord instanceof final MmsMessageRecord mmsMessage) || mmsMessage.getQuote() == null) { + return null; + } + + Recipient quoteAuthor = Recipient.resolved(mmsMessage.getQuote().getAuthor()); + return MemberLabelRepository.getInstance().getLabelJava(threadRecipient.requireGroupId().requireV2(), quoteAuthor); + } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/SenderNameWithLabelView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/SenderNameWithLabelView.kt index eda43f1937..adcdf5412f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/SenderNameWithLabelView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/SenderNameWithLabelView.kt @@ -32,6 +32,9 @@ class SenderNameWithLabelView : AbstractComposeView { private var senderName: String by mutableStateOf("") private var senderColor: Color by mutableStateOf(Color.Unspecified) + private var labelTextColor: Color by mutableStateOf(Color.Unspecified) + private var labelBackgroundColor: Color by mutableStateOf(Color.Unspecified) + private var memberLabel: MemberLabel? by mutableStateOf(null) fun setSender(name: String, @ColorInt tintColor: Int) { @@ -39,16 +42,49 @@ class SenderNameWithLabelView : AbstractComposeView { senderColor = Color(tintColor) } + /** + * Sets the label with colors derived from the sender name tint color. + */ fun setLabel(label: MemberLabel?) { memberLabel = label + labelTextColor = Color.Unspecified + labelBackgroundColor = Color.Unspecified + } + + /** + * Sets the label with explicit text and background colors. + */ + fun setLabel(label: MemberLabel?, @ColorInt textColor: Int, @ColorInt backgroundColor: Int) { + memberLabel = label + labelTextColor = Color(textColor) + labelBackgroundColor = Color(backgroundColor) + } + + /** + * Used to update the colors in response to theme changes (e.g., wallpaper enabled/disabled). + */ + fun updateColors(@ColorInt foregroundColor: Int, @ColorInt labelBackgroundColor: Int) { + senderColor = Color(foregroundColor) + labelTextColor = Color(foregroundColor) + this.labelBackgroundColor = Color(labelBackgroundColor) } @Composable override fun Content() { - SenderNameWithLabel( - senderName = senderName, - senderColor = senderColor, - label = memberLabel - ) + if (labelTextColor != Color.Unspecified || labelBackgroundColor != Color.Unspecified) { + SenderNameWithLabel( + senderName = senderName, + senderColor = senderColor, + memberLabel = memberLabel, + labelTextColor = labelTextColor, + labelBackgroundColor = labelBackgroundColor + ) + } else { + SenderNameWithLabel( + senderName = senderName, + senderColor = senderColor, + memberLabel = memberLabel + ) + } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemMediaViewHolder.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemMediaViewHolder.kt index dc3004d218..96dc940b16 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemMediaViewHolder.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/items/V2ConversationItemMediaViewHolder.kt @@ -89,7 +89,8 @@ class V2ConversationItemMediaViewHolder>( quote.attachment, if (conversationMessage.messageRecord.isStoryReaction()) conversationMessage.messageRecord.body else null, quote.quoteType, - false + false, + conversationMessage.quoteMemberLabel ) quoteView.setMessageType( diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/memberlabel/MemberLabelPill.kt b/app/src/main/java/org/thoughtcrime/securesms/groups/memberlabel/MemberLabelPill.kt index ec625a3be1..42c9474ee1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/memberlabel/MemberLabelPill.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/memberlabel/MemberLabelPill.kt @@ -25,6 +25,9 @@ import androidx.compose.ui.unit.dp import org.signal.core.ui.compose.DayNightPreviews import org.signal.core.ui.compose.Previews +private val defaultModifier = Modifier.padding(horizontal = 12.dp, vertical = 2.dp) +private val defaultTextStyle: @Composable () -> TextStyle = { MaterialTheme.typography.bodyLarge } + /** * Displays member label text with an optional emoji. */ @@ -33,8 +36,8 @@ fun MemberLabelPill( emoji: String?, text: String, tintColor: Color, - modifier: Modifier = Modifier.padding(horizontal = 12.dp, vertical = 2.dp), - textStyle: TextStyle = MaterialTheme.typography.bodyLarge + modifier: Modifier = defaultModifier, + textStyle: TextStyle = defaultTextStyle() ) { val isDark = isSystemInDarkTheme() val backgroundColor = tintColor.copy(alpha = if (isDark) 0.32f else 0.10f) @@ -45,6 +48,28 @@ fun MemberLabelPill( Color.Black.copy(alpha = 0.30f).compositeOver(tintColor) } + MemberLabelPill( + emoji = emoji, + text = text, + textColor = textColor, + backgroundColor = backgroundColor, + modifier = modifier, + textStyle = textStyle + ) +} + +/** + * Displays member label text with an optional emoji. + */ +@Composable +fun MemberLabelPill( + emoji: String?, + text: String, + textColor: Color, + backgroundColor: Color, + modifier: Modifier = defaultModifier, + textStyle: TextStyle = defaultTextStyle() +) { Row( modifier = Modifier .background( diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/memberlabel/SenderNameWithLabel.kt b/app/src/main/java/org/thoughtcrime/securesms/groups/memberlabel/SenderNameWithLabel.kt index 7fa9875e6a..3eb0bb7a6c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/memberlabel/SenderNameWithLabel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/memberlabel/SenderNameWithLabel.kt @@ -17,22 +17,83 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import org.signal.core.ui.compose.DayNightPreviews import org.signal.core.ui.compose.Previews +private val defaultLabelModifier = Modifier.padding(horizontal = 6.dp, vertical = 2.dp) +private val defaultLabelTextStyle: @Composable () -> TextStyle = { MaterialTheme.typography.bodySmall } + /** - * Displays a sender name with an optional member label pill. + * Displays a sender name with an optional member label pill with label colors derived from [senderColor]. */ @OptIn(ExperimentalLayoutApi::class) @Composable fun SenderNameWithLabel( senderName: String, senderColor: Color, - label: MemberLabel?, + memberLabel: MemberLabel?, modifier: Modifier = Modifier +) { + SenderNameWithLabel( + senderName = senderName, + senderColor = senderColor, + memberLabel = memberLabel, + modifier = modifier, + labelSlot = { label -> + MemberLabelPill( + emoji = label.emoji, + text = label.text, + tintColor = senderColor, + modifier = defaultLabelModifier, + textStyle = defaultLabelTextStyle() + ) + } + ) +} + +/** + * Displays a sender name with an optional member label pill with explicit label colors. + */ +@OptIn(ExperimentalLayoutApi::class) +@Composable +fun SenderNameWithLabel( + senderName: String, + senderColor: Color, + memberLabel: MemberLabel?, + labelTextColor: Color, + labelBackgroundColor: Color, + modifier: Modifier = Modifier +) { + SenderNameWithLabel( + senderName = senderName, + senderColor = senderColor, + memberLabel = memberLabel, + modifier = modifier, + labelSlot = { label -> + MemberLabelPill( + emoji = label.emoji, + text = label.text, + textColor = labelTextColor, + backgroundColor = labelBackgroundColor, + modifier = defaultLabelModifier, + textStyle = defaultLabelTextStyle() + ) + } + ) +} + +@OptIn(ExperimentalLayoutApi::class) +@Composable +private fun SenderNameWithLabel( + senderName: String, + senderColor: Color, + memberLabel: MemberLabel?, + modifier: Modifier = Modifier, + labelSlot: @Composable (MemberLabel) -> Unit ) { FlowRow( modifier = modifier, @@ -49,14 +110,8 @@ fun SenderNameWithLabel( overflow = TextOverflow.Ellipsis ) - if (label != null) { - MemberLabelPill( - emoji = label.emoji, - text = label.text, - tintColor = senderColor, - textStyle = MaterialTheme.typography.labelSmall, - modifier = Modifier.padding(horizontal = 6.dp, vertical = 2.dp) - ) + if (memberLabel != null) { + labelSlot(memberLabel) } } } @@ -68,7 +123,7 @@ private fun SenderNameWithLabelPreview() = Previews.Preview { SenderNameWithLabel( senderName = "Foo Bar", senderColor = Color(0xFF7C4DFF), - label = MemberLabel(emoji = "\uD83D\uDC36", text = "Vet Coordinator") + memberLabel = MemberLabel(emoji = "\uD83D\uDC36", text = "Vet Coordinator") ) } } @@ -80,7 +135,7 @@ private fun SenderNameWithLabelLongLabelPreview() = Previews.Preview { SenderNameWithLabel( senderName = "Foo Bar", senderColor = Color(0xFF7C4DFF), - label = MemberLabel(emoji = "🧠", text = "Zero-Knowledge Know-It-All") + memberLabel = MemberLabel(emoji = "🧠", text = "Zero-Knowledge Know-It-It-All") ) } } @@ -92,7 +147,7 @@ private fun SenderNameWithLabelLongNamePreview() = Previews.Preview { SenderNameWithLabel( senderName = "Cassandra NullPointer-Exception", senderColor = Color(0xFF7C4DFF), - label = MemberLabel(emoji = "🧠", text = "Vet Coordinator") + memberLabel = MemberLabel(emoji = "🧠", text = "Vet Coordinator") ) } } @@ -104,7 +159,21 @@ private fun SenderNameWithLabelNoLabelPreview() = Previews.Preview { SenderNameWithLabel( senderName = "Sam", senderColor = Color(0xFF4CAF50), - label = null + memberLabel = null + ) + } +} + +@DayNightPreviews +@Composable +private fun SenderNameWithLabelExplicitColorsPreview() = Previews.Preview { + Box(modifier = Modifier.width(200.dp)) { + SenderNameWithLabel( + senderName = "Foo Bar", + senderColor = MaterialTheme.colorScheme.onSurface, + memberLabel = MemberLabel(emoji = "\uD83D\uDC36", text = "Vet Coordinator"), + labelTextColor = MaterialTheme.colorScheme.onSurface, + labelBackgroundColor = MaterialTheme.colorScheme.surfaceVariant ) } } diff --git a/app/src/main/res/layout/v2_quote_view.xml b/app/src/main/res/layout/v2_quote_view.xml index e6aa042667..b0578dc6d1 100644 --- a/app/src/main/res/layout/v2_quote_view.xml +++ b/app/src/main/res/layout/v2_quote_view.xml @@ -19,17 +19,14 @@ app:layout_constraintTop_toTopOf="parent" tools:background="@color/signal_colorPrimary" /> - + app:layout_constraintVertical_chainStyle="packed" /> @color/signal_colorTransparent2 @color/signal_colorNeutralInverse - @color/signal_colorNeutralInverse + @color/signal_colorOnSurface @color/signal_colorTransparent4 @color/signal_colorNeutralInverse - @color/signal_colorNeutral + @color/signal_colorOnSurfaceInverse @color/signal_colorTransparent3 @color/signal_colorOnCustom @color/signal_colorOnSurface @color/signal_colorTransparent4 @color/signal_colorOnCustom - @color/signal_light_colorOnSurface + @color/signal_colorOnSurfaceInverse + @color/transparent_white_20 + @color/transparent_white_20 + @color/transparent_white_20 + @color/transparent_white_20 @color/signal_colorSurface1 diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index cb11d6a55c..02fcc5fed9 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -30,6 +30,7 @@ #33ffffff #40ffffff #4Dffffff + #5cffffff #66ffffff #99ffffff #b2ffffff diff --git a/app/src/main/res/values/light_colors.xml b/app/src/main/res/values/light_colors.xml index 56b1ad87b2..8c1a4cece0 100644 --- a/app/src/main/res/values/light_colors.xml +++ b/app/src/main/res/values/light_colors.xml @@ -178,6 +178,10 @@ @color/signal_colorTransparent4 @color/signal_colorOnCustom @color/signal_colorOnSurface + @color/signal_colorOnSurface_8 + @color/transparent_white_80 + @color/transparent_white_36 + @color/transparent_white_36 @color/signal_colorSurface1 @color/signal_colorSurfaceVariant diff --git a/core/ui/src/main/res/values-night/material3_colors.xml b/core/ui/src/main/res/values-night/material3_colors.xml index b80f6adac3..a7251a4b4b 100644 --- a/core/ui/src/main/res/values-night/material3_colors.xml +++ b/core/ui/src/main/res/values-night/material3_colors.xml @@ -45,6 +45,7 @@ @color/signal_dark_colorNeutralVariantInverse + @color/signal_light_colorOnSurface @color/signal_light_colorError @color/signal_light_colorErrorContainer diff --git a/core/ui/src/main/res/values/material3_colors.xml b/core/ui/src/main/res/values/material3_colors.xml index bef00a3662..3987d175a1 100644 --- a/core/ui/src/main/res/values/material3_colors.xml +++ b/core/ui/src/main/res/values/material3_colors.xml @@ -45,6 +45,7 @@ @color/signal_light_colorNeutralVariantInverse + @color/signal_dark_colorOnSurface @color/signal_dark_colorError @color/signal_dark_colorErrorContainer @@ -53,6 +54,7 @@ #99FBFCFF #61E7EBF3 #A3E7EBF3 + #141B1B1D #1F1B1B1D #801B1B1D #99545863