Fix CI V2 layout bounds when item has a reaction.
This commit is contained in:
parent
3040b70100
commit
4590655dc5
7 changed files with 52 additions and 31 deletions
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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" />
|
||||
|
|
Loading…
Add table
Reference in a new issue