mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-05-08 09:18:39 +01:00
Suppress LayoutTransition during scroll events.
This commit is contained in:
+1
@@ -217,6 +217,7 @@ class V2ConversationItemShapeTest {
|
|||||||
override val isMessageRequestAccepted: Boolean = true
|
override val isMessageRequestAccepted: Boolean = true
|
||||||
override val searchQuery: String? = null
|
override val searchQuery: String? = null
|
||||||
override val glideRequests: GlideRequests = mockk()
|
override val glideRequests: GlideRequests = mockk()
|
||||||
|
override val isParentInScroll: Boolean = false
|
||||||
|
|
||||||
override fun onStartExpirationTimeout(messageRecord: MessageRecord) = Unit
|
override fun onStartExpirationTimeout(messageRecord: MessageRecord) = Unit
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,10 @@ public interface BindableConversationItem extends Unbindable, GiphyMp4Playable,
|
|||||||
|
|
||||||
void setEventListener(@Nullable EventListener listener);
|
void setEventListener(@Nullable EventListener listener);
|
||||||
|
|
||||||
|
default void setParentScrolling(boolean isParentScrolling) {
|
||||||
|
// Intentionally Blank.
|
||||||
|
}
|
||||||
|
|
||||||
default void updateTimestamps() {
|
default void updateTimestamps() {
|
||||||
// Intentionally Blank.
|
// Intentionally Blank.
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ interface ConversationAdapterBridge {
|
|||||||
const val PAYLOAD_TIMESTAMP = 0
|
const val PAYLOAD_TIMESTAMP = 0
|
||||||
const val PAYLOAD_NAME_COLORS = 1
|
const val PAYLOAD_NAME_COLORS = 1
|
||||||
const val PAYLOAD_SELECTED = 2
|
const val PAYLOAD_SELECTED = 2
|
||||||
|
const val PAYLOAD_PARENT_SCROLLING = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
fun hasNoConversationMessages(): Boolean
|
fun hasNoConversationMessages(): Boolean
|
||||||
|
|||||||
@@ -418,6 +418,11 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
|||||||
this.conversationRecipient.observeForever(this);
|
this.conversationRecipient.observeForever(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setParentScrolling(boolean isParentScrolling) {
|
||||||
|
bodyBubble.setParentScrolling(isParentScrolling);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateSelectedState() {
|
public void updateSelectedState() {
|
||||||
setHasBeenQuoted(conversationMessage);
|
setHasBeenQuoted(conversationMessage);
|
||||||
|
|||||||
+18
-3
@@ -12,6 +12,7 @@ import androidx.annotation.Nullable;
|
|||||||
import com.annimon.stream.Collectors;
|
import com.annimon.stream.Collectors;
|
||||||
import com.annimon.stream.Stream;
|
import com.annimon.stream.Stream;
|
||||||
|
|
||||||
|
import org.signal.core.util.logging.Log;
|
||||||
import org.thoughtcrime.securesms.components.Outliner;
|
import org.thoughtcrime.securesms.components.Outliner;
|
||||||
import org.thoughtcrime.securesms.util.Projection;
|
import org.thoughtcrime.securesms.util.Projection;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
@@ -30,19 +31,33 @@ public class ConversationItemBodyBubble extends LinearLayout {
|
|||||||
private Projection quoteViewProjection;
|
private Projection quoteViewProjection;
|
||||||
private Projection videoPlayerProjection;
|
private Projection videoPlayerProjection;
|
||||||
|
|
||||||
|
private final BodyBubbleLayoutTransition bodyBubbleLayoutTransition = new BodyBubbleLayoutTransition();
|
||||||
|
|
||||||
public ConversationItemBodyBubble(Context context) {
|
public ConversationItemBodyBubble(Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
setLayoutTransition(new BodyBubbleLayoutTransition());
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConversationItemBodyBubble(Context context, @Nullable AttributeSet attrs) {
|
public ConversationItemBodyBubble(Context context, @Nullable AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
setLayoutTransition(new BodyBubbleLayoutTransition());
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConversationItemBodyBubble(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
public ConversationItemBodyBubble(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||||
super(context, attrs, defStyleAttr);
|
super(context, attrs, defStyleAttr);
|
||||||
setLayoutTransition(new BodyBubbleLayoutTransition());
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
setLayoutTransition(bodyBubbleLayoutTransition);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParentScrolling(boolean isParentScrolling) {
|
||||||
|
if (isParentScrolling) {
|
||||||
|
setLayoutTransition(null);
|
||||||
|
} else {
|
||||||
|
setLayoutTransition(bodyBubbleLayoutTransition);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOutliners(@NonNull List<Outliner> outliners) {
|
public void setOutliners(@NonNull List<Outliner> outliners) {
|
||||||
|
|||||||
@@ -90,6 +90,10 @@ class ConversationAdapterV2(
|
|||||||
|
|
||||||
override var isMessageRequestAccepted: Boolean = false
|
override var isMessageRequestAccepted: Boolean = false
|
||||||
|
|
||||||
|
override var isParentInScroll: Boolean = false
|
||||||
|
|
||||||
|
private val onScrollStateChangedListener = OnScrollStateChangedListener()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
registerFactory(ThreadHeader::class.java, ::ThreadHeaderViewHolder, R.layout.conversation_item_thread_header)
|
registerFactory(ThreadHeader::class.java, ::ThreadHeaderViewHolder, R.layout.conversation_item_thread_header)
|
||||||
|
|
||||||
@@ -162,6 +166,8 @@ class ConversationAdapterV2(
|
|||||||
recyclerView.recycledViewPool.setMaxRecycledViews(type, count)
|
recyclerView.recycledViewPool.setMaxRecycledViews(type, count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
recyclerView.addOnScrollListener(onScrollStateChangedListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewRecycled(holder: MappingViewHolder<*>) {
|
override fun onViewRecycled(holder: MappingViewHolder<*>) {
|
||||||
@@ -176,6 +182,8 @@ class ConversationAdapterV2(
|
|||||||
.children
|
.children
|
||||||
.filterIsInstance<Unbindable>()
|
.filterIsInstance<Unbindable>()
|
||||||
.forEach { it.unbind() }
|
.forEach { it.unbind() }
|
||||||
|
|
||||||
|
recyclerView.removeOnScrollListener(onScrollStateChangedListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val displayMode: ConversationItemDisplayMode
|
override val displayMode: ConversationItemDisplayMode
|
||||||
@@ -498,6 +506,11 @@ class ConversationAdapterV2(
|
|||||||
fun bindPayloadsIfAvailable(): Boolean {
|
fun bindPayloadsIfAvailable(): Boolean {
|
||||||
var payloadApplied = false
|
var payloadApplied = false
|
||||||
|
|
||||||
|
bindable.setParentScrolling(isParentInScroll)
|
||||||
|
if (payload.contains(ConversationAdapterBridge.PAYLOAD_PARENT_SCROLLING)) {
|
||||||
|
payloadApplied = true
|
||||||
|
}
|
||||||
|
|
||||||
if (payload.contains(ConversationAdapterBridge.PAYLOAD_TIMESTAMP)) {
|
if (payload.contains(ConversationAdapterBridge.PAYLOAD_TIMESTAMP)) {
|
||||||
bindable.updateTimestamps()
|
bindable.updateTimestamps()
|
||||||
payloadApplied = true
|
payloadApplied = true
|
||||||
@@ -627,4 +640,14 @@ class ConversationAdapterV2(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private inner class OnScrollStateChangedListener : RecyclerView.OnScrollListener() {
|
||||||
|
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||||
|
val oldState = isParentInScroll
|
||||||
|
isParentInScroll = newState != RecyclerView.SCROLL_STATE_IDLE
|
||||||
|
if (isParentInScroll != oldState) {
|
||||||
|
notifyItemRangeChanged(0, itemCount, ConversationAdapterBridge.PAYLOAD_PARENT_SCROLLING)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -23,6 +23,7 @@ interface V2ConversationContext {
|
|||||||
val selectedItems: Set<MultiselectPart>
|
val selectedItems: Set<MultiselectPart>
|
||||||
val isMessageRequestAccepted: Boolean
|
val isMessageRequestAccepted: Boolean
|
||||||
val searchQuery: String?
|
val searchQuery: String?
|
||||||
|
val isParentInScroll: Boolean
|
||||||
|
|
||||||
fun onStartExpirationTimeout(messageRecord: MessageRecord)
|
fun onStartExpirationTimeout(messageRecord: MessageRecord)
|
||||||
|
|
||||||
|
|||||||
+18
-2
@@ -100,6 +100,7 @@ open class V2ConversationItemTextOnlyViewHolder<Model : MappingModel<Model>>(
|
|||||||
|
|
||||||
private val bodyBubbleDrawable = ChatColorsDrawable()
|
private val bodyBubbleDrawable = ChatColorsDrawable()
|
||||||
private val footerDrawable = ChatColorsDrawable()
|
private val footerDrawable = ChatColorsDrawable()
|
||||||
|
private val bodyBubbleLayoutTransition = BodyBubbleLayoutTransition()
|
||||||
|
|
||||||
protected lateinit var shape: V2ConversationItemShape.MessageShape
|
protected lateinit var shape: V2ConversationItemShape.MessageShape
|
||||||
|
|
||||||
@@ -155,7 +156,7 @@ open class V2ConversationItemTextOnlyViewHolder<Model : MappingModel<Model>>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
binding.conversationItemBodyWrapper.background = bodyBubbleDrawable
|
binding.conversationItemBodyWrapper.background = bodyBubbleDrawable
|
||||||
binding.conversationItemBodyWrapper.layoutTransition = BodyBubbleLayoutTransition()
|
binding.conversationItemBodyWrapper.layoutTransition = bodyBubbleLayoutTransition
|
||||||
|
|
||||||
binding.conversationItemFooterBackground.background = footerDrawable
|
binding.conversationItemFooterBackground.background = footerDrawable
|
||||||
}
|
}
|
||||||
@@ -166,6 +167,22 @@ open class V2ConversationItemTextOnlyViewHolder<Model : MappingModel<Model>>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun bind(model: Model) {
|
override fun bind(model: Model) {
|
||||||
|
var hasProcessedSupportedPayload = false
|
||||||
|
|
||||||
|
binding.conversationItemBodyWrapper.layoutTransition = if (conversationContext.isParentInScroll) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
bodyBubbleLayoutTransition
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ConversationAdapterBridge.PAYLOAD_PARENT_SCROLLING in payload) {
|
||||||
|
if (payload.size == 1) {
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
hasProcessedSupportedPayload = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
check(model is ConversationMessageElement)
|
check(model is ConversationMessageElement)
|
||||||
conversationMessage = model.conversationMessage
|
conversationMessage = model.conversationMessage
|
||||||
|
|
||||||
@@ -176,7 +193,6 @@ open class V2ConversationItemTextOnlyViewHolder<Model : MappingModel<Model>>(
|
|||||||
adapterPosition = bindingAdapterPosition
|
adapterPosition = bindingAdapterPosition
|
||||||
)
|
)
|
||||||
|
|
||||||
var hasProcessedSupportedPayload = false
|
|
||||||
if (ConversationAdapterBridge.PAYLOAD_TIMESTAMP in payload) {
|
if (ConversationAdapterBridge.PAYLOAD_TIMESTAMP in payload) {
|
||||||
presentDate()
|
presentDate()
|
||||||
hasProcessedSupportedPayload = true
|
hasProcessedSupportedPayload = true
|
||||||
|
|||||||
Reference in New Issue
Block a user