Fix CI V2 layout bounds when item has a reaction.

This commit is contained in:
Alex Hart 2023-06-30 16:12:43 -03:00 committed by Greyson Parrelli
parent 3040b70100
commit 4590655dc5
7 changed files with 52 additions and 31 deletions

View file

@ -18,20 +18,24 @@ class V2ConversationItemLayout @JvmOverloads constructor(
attrs: AttributeSet? = null
) : ConstraintLayout(context, attrs) {
private var onMeasureListener: OnMeasureListener? = null
private var onMeasureListeners: Set<OnMeasureListener> = emptySet()
/**
* Set the onMeasureListener to be invoked by this view whenever onMeasure is called.
*/
fun setOnMeasureListener(onMeasureListener: OnMeasureListener?) {
this.onMeasureListener = onMeasureListener
fun addOnMeasureListener(onMeasureListener: OnMeasureListener) {
this.onMeasureListeners += onMeasureListener
}
fun removeOnMeasureListener(onMeasureListener: OnMeasureListener) {
this.onMeasureListeners -= onMeasureListener
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
onMeasureListener?.onPreMeasure()
onMeasureListeners.forEach { it.onPreMeasure() }
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
val remeasure = onMeasureListener?.onPostMeasure() ?: false
val remeasure = onMeasureListeners.map { it.onPostMeasure() }.any { it }
if (remeasure) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
}

View file

@ -28,7 +28,7 @@ class V2ConversationItemShape(
private var smallRadius: Float = 4f.dp
private var collapsedSpacing: Float = 1f.dp
private var defaultSpacing: Float = 8f.dp
private var defaultSpacing: Float = 6f.dp
private val clusterTimeout = 3.minutes
}
@ -41,9 +41,6 @@ class V2ConversationItemShape(
)
private set
var spacing: Pair<Float, Float> = Pair(defaultSpacing, defaultSpacing)
private set
/**
* Sets the message spacing and corners based off the given information. This
* updates the class state.
@ -59,25 +56,21 @@ class V2ConversationItemShape(
if (isSingularMessage(currentMessage, previousMessage, nextMessage, isGroupThread)) {
setBodyBubbleCorners(isLtr, bigRadius, bigRadius, bigRadius, bigRadius)
spacing = Pair(defaultSpacing, defaultSpacing)
return MessageShape.SINGLE
} else if (isStartOfMessageCluster(currentMessage, previousMessage, isGroupThread)) {
val bottomEnd = if (currentMessage.isOutgoing) smallRadius else bigRadius
val bottomStart = if (currentMessage.isOutgoing) bigRadius else smallRadius
setBodyBubbleCorners(isLtr, bigRadius, bigRadius, bottomEnd, bottomStart)
spacing = Pair(defaultSpacing, collapsedSpacing)
return MessageShape.START
} else if (isEndOfMessageCluster(currentMessage, nextMessage)) {
val topStart = if (currentMessage.isOutgoing) bigRadius else smallRadius
val topEnd = if (currentMessage.isOutgoing) smallRadius else bigRadius
setBodyBubbleCorners(isLtr, topStart, topEnd, bigRadius, bigRadius)
spacing = Pair(collapsedSpacing, defaultSpacing)
return MessageShape.END
} else {
val start = if (currentMessage.isOutgoing) bigRadius else smallRadius
val end = if (currentMessage.isOutgoing) smallRadius else bigRadius
setBodyBubbleCorners(isLtr, start, end, end, start)
spacing = Pair(collapsedSpacing, collapsedSpacing)
return MessageShape.MIDDLE
}
}
@ -156,25 +149,28 @@ class V2ConversationItemShape(
return abs(currentMessage.dateSent - previousMessage.dateSent) <= clusterTimeout.inWholeMilliseconds
}
enum class MessageShape {
enum class MessageShape(
val topPadding: Float,
val bottomPadding: Float
) {
/**
* This message stands alone.
*/
SINGLE,
SINGLE(defaultSpacing, defaultSpacing),
/**
* This message is the start of a cluster
*/
START,
START(defaultSpacing, collapsedSpacing),
/**
* This message is the end of a cluster
*/
END,
END(collapsedSpacing, defaultSpacing),
/**
* This message is in the middle of a cluster
*/
MIDDLE
MIDDLE(collapsedSpacing, collapsedSpacing)
}
}

View file

@ -7,6 +7,8 @@ package org.thoughtcrime.securesms.conversation.v2.items
import android.view.View
import android.view.ViewGroup
import android.view.ViewGroup.MarginLayoutParams
import androidx.core.view.updateLayoutParams
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.shape.MaterialShapeDrawable
import com.google.android.material.shape.ShapeAppearanceModel
@ -24,7 +26,6 @@ import org.thoughtcrime.securesms.util.DateUtils
import org.thoughtcrime.securesms.util.Projection
import org.thoughtcrime.securesms.util.ProjectionList
import org.thoughtcrime.securesms.util.SignalLocalMetrics
import org.thoughtcrime.securesms.util.ViewUtil
import org.thoughtcrime.securesms.util.adapter.mapping.MappingModel
import org.thoughtcrime.securesms.util.adapter.mapping.MappingViewHolder
import org.thoughtcrime.securesms.util.hasNoBubble
@ -81,8 +82,10 @@ class V2TextOnlyViewHolder<Model : MappingModel<Model>>(
override val contactPhotoHolderView: View? = binding.senderPhoto
override val badgeImageView: View? = binding.senderBadge
private var reactionMeasureListener: ReactionMeasureListener = ReactionMeasureListener()
init {
binding.root.setOnMeasureListener(footerDelegate)
binding.root.addOnMeasureListener(footerDelegate)
}
override fun bind(model: Model) {
@ -116,10 +119,12 @@ class V2TextOnlyViewHolder<Model : MappingModel<Model>>(
presentFooterExpiry(shape)
presentAlert()
presentSender()
presentReactions()
val (topPadding, bottomPadding) = shapeDelegate.spacing
ViewUtil.setPaddingTop(itemView, topPadding.toInt())
ViewUtil.setPaddingBottom(itemView, bottomPadding.toInt())
itemView.updateLayoutParams<MarginLayoutParams> {
topMargin = shape.topPadding.toInt()
bottomMargin = shape.bottomPadding.toInt()
}
}
override fun getAdapterPosition(recyclerView: RecyclerView): Int = bindingAdapterPosition
@ -245,6 +250,16 @@ class V2TextOnlyViewHolder<Model : MappingModel<Model>>(
}
}
private fun presentReactions() {
if (conversationMessage.messageRecord.reactions.isEmpty()) {
binding.conversationItemReactions.clear()
binding.root.removeOnMeasureListener(reactionMeasureListener)
} else {
reactionMeasureListener.onPostMeasure()
binding.root.addOnMeasureListener(reactionMeasureListener)
}
}
private fun presentFooterBackground(shape: V2ConversationItemShape.MessageShape) {
if (!binding.conversationItemBody.isJumbomoji ||
!conversationContext.hasWallpaper() ||
@ -347,4 +362,12 @@ class V2TextOnlyViewHolder<Model : MappingModel<Model>>(
override fun disallowSwipe(latestDownX: Float, latestDownY: Float): Boolean {
return false
}
private inner class ReactionMeasureListener : V2ConversationItemLayout.OnMeasureListener {
override fun onPreMeasure() = Unit
override fun onPostMeasure(): Boolean {
return binding.conversationItemReactions.setReactions(conversationMessage.messageRecord.reactions, binding.conversationItemBodyWrapper.width)
}
}
}

View file

@ -63,9 +63,9 @@ public class ReactionsConversationView extends LinearLayout {
removeAllViews();
}
public void setReactions(@NonNull List<ReactionRecord> records, int bubbleWidth) {
public boolean setReactions(@NonNull List<ReactionRecord> records, int bubbleWidth) {
if (records.equals(this.records) && this.bubbleWidth == bubbleWidth) {
return;
return false;
}
this.records.clear();
@ -102,6 +102,8 @@ public class ReactionsConversationView extends LinearLayout {
ViewUtil.setLeftMargin(this, OUTER_MARGIN);
}
}
return true;
}
private static @NonNull List<Reaction> buildSortedReactionsList(@NonNull List<ReactionRecord> records) {

View file

@ -62,7 +62,6 @@
android:orientation="vertical"
app:cardElevation="0dp"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toEndOf="@id/contact_photo"
@ -157,7 +156,6 @@
android:layout_height="wrap_content"
android:layout_marginTop="-4dp"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@id/conversation_item_body_wrapper"
app:layout_constraintTop_toBottomOf="@id/conversation_item_body_wrapper"
app:rcv_outgoing="false" />

View file

@ -35,7 +35,6 @@
android:layout_marginStart="48dp"
app:cardElevation="0dp"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/conversation_item_alert"
app:layout_constraintHorizontal_bias="1"
app:layout_constraintStart_toStartOf="parent"
@ -152,7 +151,6 @@
android:layout_height="wrap_content"
android:layout_marginTop="-4dp"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@id/conversation_item_body_wrapper"
app:layout_constraintTop_toBottomOf="@id/conversation_item_body_wrapper"
app:rcv_outgoing="false" />