Fix sender name/label clipping in recycled conversation items.

Resolves signalapp/Signal-Android#14646
This commit is contained in:
jeffrey-signal
2026-04-15 11:50:11 -04:00
parent c30e3cc1b7
commit 2a8bd20bb0
5 changed files with 39 additions and 13 deletions

View File

@@ -289,8 +289,7 @@ public class QuoteView extends ConstraintLayout implements RecipientForeverObser
QuoteViewColorTheme colorTheme = getColorTheme();
int foregroundColor = colorTheme.getForegroundColor(getContext());
authorView.setSender(name, foregroundColor);
authorView.setLabel(memberLabel, foregroundColor, colorTheme.getLabelBackgroundColor(getContext()));
authorView.bind(name, foregroundColor, memberLabel, foregroundColor, colorTheme.getLabelBackgroundColor(getContext()));
}
private boolean isStoryReply() {

View File

@@ -2026,8 +2026,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
if (groupThread && !messageRecord.isOutgoing()) {
String senderName = recipient.getDisplayName(getContext());
int senderColor = colorizer.getIncomingGroupSenderColor(getContext(), messageRecord.getFromRecipient());
senderWithLabelView.setSender(senderName, senderColor);
senderWithLabelView.setLabel(conversationMessage.getMemberLabel());
senderWithLabelView.bind(senderName, senderColor, conversationMessage.getMemberLabel());
}
}

View File

@@ -27,7 +27,7 @@ class SenderNameWithLabelView : AbstractComposeView {
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
init {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setViewCompositionStrategy(ViewCompositionStrategy.Default)
}
private var senderName: String by mutableStateOf("")
@@ -37,6 +37,28 @@ class SenderNameWithLabelView : AbstractComposeView {
private var memberLabel: MemberLabel? by mutableStateOf(null)
/**
* Sets sender and label state and forces fresh composition to avoid stale measurements from a previously bound item.
* Intended for use in a RecyclerView.
*/
fun bind(name: String, @ColorInt tintColor: Int, label: MemberLabel?) {
setSender(name, tintColor)
setLabel(label)
// AbstractComposeView caches measurements across RecyclerView recycling. This forces fresh composition on the
// next measure to avoid stale cached measurements during recycling that can cause sender name / label clipping.
disposeComposition()
}
/**
* Variant of [bind] with explicit label text/background colors.
*/
fun bind(name: String, @ColorInt tintColor: Int, label: MemberLabel?, @ColorInt textColor: Int, @ColorInt backgroundColor: Int) {
setSender(name, tintColor)
setLabel(label, textColor, backgroundColor)
disposeComposition()
}
fun setSender(name: String, @ColorInt tintColor: Int) {
senderName = name
senderColor = Color(tintColor)

View File

@@ -631,8 +631,7 @@ open class V2ConversationItemTextOnlyViewHolder<Model : MappingModel<Model>>(
val tintColor = conversationContext.getColorizer().getIncomingGroupSenderColor(context, sender)
nameWithLabelView.apply {
setSender(sender.getDisplayName(context), tintColor)
setLabel(conversationMessage.memberLabel)
bind(sender.getDisplayName(context), tintColor, conversationMessage.memberLabel)
visible = true
}