That fuck shit the fascists are using
at master 76 lines 3.2 kB view raw
1/* 2 * Copyright 2023 Signal Messenger, LLC 3 * SPDX-License-Identifier: AGPL-3.0-only 4 */ 5 6package androidx.recyclerview.widget 7 8import android.content.Context 9import org.signal.core.util.logging.Log 10 11/** 12 * Variation of a vertical, reversed [LinearLayoutManager] that makes specific assumptions in how it will 13 * be used by Conversation view to support easier scrolling to the initial start position. 14 * 15 * Primarily, it assumes that an initial scroll to position call will always happen and that the implementation 16 * of [LinearLayoutManager] remains unchanged with respect to how it assigns [mPendingScrollPosition] and 17 * [mPendingScrollPositionOffset] in [LinearLayoutManager.scrollToPositionWithOffset] and how it always clears 18 * the pending state variables in every call to [LinearLayoutManager.onLayoutCompleted]. 19 * 20 * The assumptions are necessary to force the requested scroll position/layout to occur even if the request 21 * happens prior to the data source populating the recycler view/adapter. 22 */ 23class ConversationLayoutManager(context: Context) : LinearLayoutManager(context, RecyclerView.VERTICAL, true) { 24 25 private var afterScroll: (() -> Unit)? = null 26 27 override fun supportsPredictiveItemAnimations(): Boolean { 28 return false 29 } 30 31 /** 32 * Scroll to the desired position and be notified when the layout manager has completed the request 33 * via [afterScroll] callback. 34 */ 35 fun scrollToPositionWithOffset(position: Int, offset: Int, afterScroll: () -> Unit) { 36 this.afterScroll = afterScroll 37 super.scrollToPositionWithOffset(position, offset) 38 } 39 40 /** 41 * If a scroll to position request is made and a layout pass occurs prior to the list being populated with via the data source, 42 * the base implementation clears the request as if it was never made. 43 * 44 * This override will capture the pending scroll position and offset, determine if the scroll request was satisfied, and 45 * re-request the scroll to position to force another attempt if not satisfied. 46 * 47 * A pending scroll request will be re-requested if the pending scroll position is outside the bounds of the current known size of 48 * items in the list. 49 */ 50 override fun onLayoutCompleted(state: RecyclerView.State?) { 51 val pendingScrollPosition = mPendingScrollPosition 52 val pendingScrollOffset = mPendingScrollPositionOffset 53 54 val reRequestPendingPosition = pendingScrollPosition >= (state?.mItemCount ?: 0) 55 56 // Base implementation always clears mPendingScrollPosition+mPendingScrollPositionOffset 57 super.onLayoutCompleted(state) 58 59 // Re-request scroll to position request if necessary thus forcing mPendingScrollPosition+mPendingScrollPositionOffset to be re-assigned 60 if (reRequestPendingPosition) { 61 Log.d(TAG, "Re-requesting pending scroll position: $pendingScrollPosition offset: $pendingScrollOffset") 62 if (pendingScrollOffset != INVALID_OFFSET) { 63 scrollToPositionWithOffset(pendingScrollPosition, pendingScrollOffset) 64 } else { 65 scrollToPosition(pendingScrollPosition) 66 } 67 } else { 68 afterScroll?.invoke() 69 afterScroll = null 70 } 71 } 72 73 companion object { 74 private val TAG = Log.tag(ConversationLayoutManager::class.java) 75 } 76}