mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-27 13:13:43 +00:00
Fix pool limits and y-translation issues with CFv2 recycler view.
This commit is contained in:
@@ -10,6 +10,7 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.text.HtmlCompat
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.exoplayer2.MediaItem
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.signal.core.util.toOptional
|
||||
@@ -74,7 +75,7 @@ class ConversationAdapterV2(
|
||||
private val condensedMode: ConversationItemDisplayMode? = null
|
||||
|
||||
init {
|
||||
registerFactory(ThreadHeader::class.java, ::ThreadHeaderViewHolder, R.layout.conversation_item_banner)
|
||||
registerFactory(ThreadHeader::class.java, ::ThreadHeaderViewHolder, R.layout.conversation_item_thread_header)
|
||||
|
||||
registerFactory(ConversationUpdate::class.java) { parent ->
|
||||
val view = CachedInflater.from(parent.context).inflate<View>(R.layout.conversation_item_update, parent, false)
|
||||
@@ -102,6 +103,27 @@ class ConversationAdapterV2(
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
|
||||
super.onAttachedToRecyclerView(recyclerView)
|
||||
|
||||
for ((model, type) in itemTypes) {
|
||||
val count: Int = when (model) {
|
||||
ThreadHeader::class.java -> 1
|
||||
ConversationUpdate::class.java -> 5
|
||||
OutgoingTextOnly::class.java -> 25
|
||||
OutgoingMedia::class.java -> 15
|
||||
IncomingTextOnly::class.java -> 25
|
||||
IncomingMedia::class.java -> 15
|
||||
Placeholder::class.java -> 5
|
||||
else -> 0
|
||||
}
|
||||
|
||||
if (count > 0) {
|
||||
recyclerView.recycledViewPool.setMaxRecycledViews(type, count)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** [messagePosition] is one-based index and adapter is zero-based. */
|
||||
fun getAdapterPositionForMessagePosition(messagePosition: Int): Int {
|
||||
return messagePosition - 1
|
||||
|
||||
@@ -13,9 +13,11 @@ import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffColorFilter
|
||||
import android.graphics.Rect
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.provider.Settings
|
||||
@@ -38,6 +40,7 @@ import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.app.ActivityOptionsCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
@@ -114,6 +117,7 @@ import org.thoughtcrime.securesms.contactshare.SharedContactDetailsActivity
|
||||
import org.thoughtcrime.securesms.conversation.AttachmentKeyboardButton
|
||||
import org.thoughtcrime.securesms.conversation.BadDecryptLearnMoreDialog
|
||||
import org.thoughtcrime.securesms.conversation.ConversationAdapter
|
||||
import org.thoughtcrime.securesms.conversation.ConversationHeaderView
|
||||
import org.thoughtcrime.securesms.conversation.ConversationIntents
|
||||
import org.thoughtcrime.securesms.conversation.ConversationIntents.ConversationScreenType
|
||||
import org.thoughtcrime.securesms.conversation.ConversationItem
|
||||
@@ -321,6 +325,7 @@ class ConversationFragment : LoggingFragment(R.layout.v2_conversation_fragment)
|
||||
private lateinit var attachmentManager: AttachmentManager
|
||||
private lateinit var multiselectItemDecoration: MultiselectItemDecoration
|
||||
private lateinit var openableGiftItemDecoration: OpenableGiftItemDecoration
|
||||
private lateinit var threadHeaderMarginDecoration: ThreadHeaderMarginDecoration
|
||||
|
||||
private var animationsAllowed = false
|
||||
private var actionMode: ActionMode? = null
|
||||
@@ -394,6 +399,8 @@ class ConversationFragment : LoggingFragment(R.layout.v2_conversation_fragment)
|
||||
.addTo(disposables)
|
||||
|
||||
container.fragmentManager = childFragmentManager
|
||||
|
||||
ToolbarDependentMarginListener(binding.toolbar)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
@@ -422,6 +429,11 @@ class ConversationFragment : LoggingFragment(R.layout.v2_conversation_fragment)
|
||||
EventBus.getDefault().unregister(this)
|
||||
}
|
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||
super.onConfigurationChanged(newConfig)
|
||||
ToolbarDependentMarginListener(binding.toolbar)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
if (pinnedShortcutReceiver != null) {
|
||||
@@ -861,7 +873,6 @@ class ConversationFragment : LoggingFragment(R.layout.v2_conversation_fragment)
|
||||
adapter::getAdapterPositionForMessagePosition
|
||||
)
|
||||
|
||||
ConversationAdapter.initializePool(binding.conversationItemRecycler.recycledViewPool)
|
||||
adapter.setPagingController(viewModel.pagingController)
|
||||
|
||||
recyclerViewColorizer = RecyclerViewColorizer(binding.conversationItemRecycler)
|
||||
@@ -895,6 +906,9 @@ class ConversationFragment : LoggingFragment(R.layout.v2_conversation_fragment)
|
||||
true
|
||||
}
|
||||
)
|
||||
|
||||
threadHeaderMarginDecoration = ThreadHeaderMarginDecoration()
|
||||
binding.conversationItemRecycler.addItemDecoration(threadHeaderMarginDecoration)
|
||||
}
|
||||
|
||||
private fun initializeGiphyMp4(): GiphyMp4ProjectionRecycler {
|
||||
@@ -2654,4 +2668,30 @@ class ConversationFragment : LoggingFragment(R.layout.v2_conversation_fragment)
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
private inner class ToolbarDependentMarginListener(private val toolbar: Toolbar) : ViewTreeObserver.OnGlobalLayoutListener {
|
||||
|
||||
init {
|
||||
toolbar.viewTreeObserver.addOnGlobalLayoutListener(this)
|
||||
}
|
||||
|
||||
override fun onGlobalLayout() {
|
||||
val rect = Rect()
|
||||
toolbar.getGlobalVisibleRect(rect)
|
||||
threadHeaderMarginDecoration.toolbarMargin = rect.bottom + 16.dp
|
||||
binding.conversationItemRecycler.invalidateItemDecorations()
|
||||
toolbar.viewTreeObserver.removeOnGlobalLayoutListener(this)
|
||||
}
|
||||
}
|
||||
|
||||
private inner class ThreadHeaderMarginDecoration : RecyclerView.ItemDecoration() {
|
||||
var toolbarMargin: Int = 0
|
||||
|
||||
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
|
||||
super.getItemOffsets(outRect, view, parent, state)
|
||||
if (view is ConversationHeaderView) {
|
||||
outRect.top = toolbarMargin
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.thoughtcrime.securesms.giph.mp4
|
||||
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Rect
|
||||
import androidx.core.view.children
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import org.thoughtcrime.securesms.conversation.ConversationAdapter
|
||||
@@ -27,18 +28,28 @@ class GiphyMp4ItemDecoration(
|
||||
parent.translationY = 0f
|
||||
onRecyclerVerticalTranslationSet(parent.translationY)
|
||||
} else {
|
||||
val footerViewHolder = parent.children
|
||||
val threadHeaderViewHolder = parent.children
|
||||
.map { parent.getChildViewHolder(it) }
|
||||
.filter { it is ConversationAdapter.FooterViewHolder || it is ConversationAdapterV2.ThreadHeaderViewHolder }
|
||||
.firstOrNull()
|
||||
|
||||
if (footerViewHolder == null) {
|
||||
if (threadHeaderViewHolder == null) {
|
||||
parent.translationY = 0f
|
||||
onRecyclerVerticalTranslationSet(parent.translationY)
|
||||
return
|
||||
}
|
||||
|
||||
val childTop: Int = footerViewHolder.itemView.top
|
||||
val toolbarMargin = if (threadHeaderViewHolder is ConversationAdapterV2.ThreadHeaderViewHolder) {
|
||||
// A decorator adds the margin for the toolbar, margin is difference of the bounds "height" and the view height
|
||||
val bounds = Rect()
|
||||
parent.getDecoratedBoundsWithMargins(threadHeaderViewHolder.itemView, bounds)
|
||||
bounds.bottom - bounds.top - threadHeaderViewHolder.itemView.height
|
||||
} else {
|
||||
// Deprecated not needed for CFv2
|
||||
0
|
||||
}
|
||||
|
||||
val childTop: Int = threadHeaderViewHolder.itemView.top - toolbarMargin
|
||||
parent.translationY = min(0, -childTop).toFloat()
|
||||
onRecyclerVerticalTranslationSet(parent.translationY)
|
||||
}
|
||||
|
||||
@@ -89,6 +89,10 @@ public class MappingAdapter extends ListAdapter<MappingModel<?>, MappingViewHold
|
||||
registerFactory(clazz, new LayoutFactory<>(creator, layout));
|
||||
}
|
||||
|
||||
public Map<Class<?>, Integer> getItemTypes() {
|
||||
return new HashMap<>(itemTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
Integer type = itemTypes.get(getItem(position).getClass());
|
||||
|
||||
@@ -93,7 +93,7 @@ public class PagingMappingAdapter<Key> extends MappingAdapter {
|
||||
return getItem(position) != null;
|
||||
}
|
||||
|
||||
private static class Placeholder implements MappingModel<Placeholder> {
|
||||
protected static class Placeholder implements MappingModel<Placeholder> {
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull Placeholder newItem) {
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user