Refactor EasyRecyclerView

This commit is contained in:
tarsin committed 2023-07-16 21:59:48 +08:00
1 parent 935c8e7d15
commit 9b3ffd1f2c
6 files changed
+147 -503

No files matched your search

@@ -1,470 +0,0 @@
/*
* Copyright (C) 2015 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.ui.legacy
import android.content.Context
import android.os.Parcel
import android.os.Parcelable
import android.util.AttributeSet
import android.util.SparseBooleanArray
import android.view.View
import android.widget.Checkable
import androidx.collection.LongSparseArray
import androidx.core.os.ParcelCompat.readParcelable
import androidx.recyclerview.widget.RecyclerView
class EasyRecyclerView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0,
) : RecyclerView(context, attrs, defStyle) {
// Fling friction
private var pageScrollThreshold = 0f
/**
* Controls if/how the user may choose/check items in the list
*/
private var mChoiceMode = CHOICE_MODE_NONE
/**
* Listener for custom multiple choices
*/
private var mCustomChoiceListener: CustomChoiceListener? = null
var isInCustomChoice = false
private set
/**
* A lock, avoid OutOfCustomChoiceMode when doing OutOfCustomChoiceMode
*/
private var mOutOfCustomChoiceModing = false
private var mTempCheckStates: SparseBooleanArray? = null
/**
* Running count of how many items are currently checked
*/
var checkedItemCount = 0
private set
/**
* Running state of which positions are currently checked
*/
private var mCheckStates: SparseBooleanArray? = null
/**
* Running state of which IDs are currently checked.
* If there is a value for a given key, the checked state for that ID is true
* and the value holds the last known position in the adapter for that id.
*/
private var mCheckedIdStates: LongSparseArray<Int>? = null
private var mAdapter: Adapter<*>? = null
/**
* {@inheritDoc}
*/
override fun setAdapter(adapter: Adapter<*>?) {
super.setAdapter(adapter)
mAdapter = adapter
if (adapter != null) {
if (mChoiceMode != CHOICE_MODE_NONE && adapter.hasStableIds() && mCheckedIdStates == null) {
mCheckedIdStates = LongSparseArray()
}
}
if (mCheckStates != null) {
mCheckStates!!.clear()
}
if (mCheckedIdStates != null) {
mCheckedIdStates!!.clear()
}
}
override fun onChildAttachedToWindow(child: View) {
super.onChildAttachedToWindow(child)
if (mCheckStates != null) {
val position = getChildAdapterPosition(child)
if (position >= 0) {
setViewChecked(child, mCheckStates!![position])
}
}
}
/**
* Returns the checked state of the specified position. The result is only
* valid if the choice mode has been set to [.CHOICE_MODE_SINGLE]
* or [.CHOICE_MODE_MULTIPLE].
*
* @param position The item whose checked state to return
* @return The item's checked state or `false` if choice mode
* is invalid
* @see .setChoiceMode
*/
fun isItemChecked(position: Int): Boolean {
return if (mChoiceMode != CHOICE_MODE_NONE && mCheckStates != null) {
mCheckStates!![position]
} else {
false
}
}
val checkedItemPositions: SparseBooleanArray?
/**
* Returns the set of checked items in the list. The result is only valid if
* the choice mode has not been set to [.CHOICE_MODE_NONE].
*
* @return A SparseBooleanArray which will return true for each call to
* get(int position) where position is a checked position in the
* list and false otherwise, or `null` if the choice
* mode is set to [.CHOICE_MODE_NONE].
*/
get() = if (mChoiceMode != CHOICE_MODE_NONE) {
mCheckStates
} else {
null
}
fun intoCustomChoiceMode() {
if (mChoiceMode == CHOICE_MODE_MULTIPLE_CUSTOM && !isInCustomChoice) {
isInCustomChoice = true
mCustomChoiceListener!!.onIntoCustomChoice(this)
}
}
fun outOfCustomChoiceMode() {
if (mChoiceMode == CHOICE_MODE_MULTIPLE_CUSTOM && isInCustomChoice && !mOutOfCustomChoiceModing) {
mOutOfCustomChoiceModing = true
// Copy mCheckStates
mTempCheckStates!!.clear()
run {
for (i in 0 until mCheckStates!!.size()) {
mTempCheckStates!!.put(mCheckStates!!.keyAt(i), mCheckStates!!.valueAt(i))
}
}
// Uncheck remain checked items
for (i in 0 until mTempCheckStates!!.size()) {
if (mTempCheckStates!!.valueAt(i)) {
setItemChecked(mTempCheckStates!!.keyAt(i), false)
}
}
isInCustomChoice = false
mCustomChoiceListener!!.onOutOfCustomChoice(this)
mOutOfCustomChoiceModing = false
}
}
/**
* Clear any choices previously set
*/
private fun clearChoices() {
if (mCheckStates != null) {
mCheckStates!!.clear()
}
if (mCheckedIdStates != null) {
mCheckedIdStates!!.clear()
}
checkedItemCount = 0
updateOnScreenCheckedViews()
}
/**
* Sets all items checked.
*/
fun checkAll() {
if (mChoiceMode == CHOICE_MODE_NONE) {
return
}
// Check is intoCheckMode
check(!(mChoiceMode == CHOICE_MODE_MULTIPLE_CUSTOM && !isInCustomChoice)) { "Call intoCheckMode first" }
for (i in 0 until mAdapter!!.itemCount) {
val oldValue = mCheckStates!![i]
mCheckStates!!.put(i, true)
if (mCheckedIdStates != null && mAdapter!!.hasStableIds()) {
mCheckedIdStates!!.put(mAdapter!!.getItemId(i), i)
}
if (!oldValue) {
checkedItemCount++
}
if (mChoiceMode == CHOICE_MODE_MULTIPLE_CUSTOM) {
val id = mAdapter!!.getItemId(i)
mCustomChoiceListener!!.onItemCheckedStateChanged(this, i, id, true)
}
}
updateOnScreenCheckedViews()
}
fun toggleItemChecked(position: Int) {
if (mCheckStates != null) {
setItemChecked(position, !mCheckStates!![position])
}
}
/**
* Sets the checked state of the specified position. The is only valid if
* the choice mode has been set to [.CHOICE_MODE_SINGLE] or
* [.CHOICE_MODE_MULTIPLE].
*
* @param position The item whose checked state is to be checked
* @param value The new checked state for the item
*/
fun setItemChecked(position: Int, value: Boolean) {
if (mChoiceMode == CHOICE_MODE_NONE) {
return
}
// Check is intoCheckMode
check(!(mChoiceMode == CHOICE_MODE_MULTIPLE_CUSTOM && !isInCustomChoice)) { "Call intoCheckMode first" }
if (mChoiceMode == CHOICE_MODE_MULTIPLE_CUSTOM) {
val oldValue = mCheckStates!![position]
mCheckStates!!.put(position, value)
if (mCheckedIdStates != null && mAdapter!!.hasStableIds()) {
if (value) {
mCheckedIdStates!!.put(mAdapter!!.getItemId(position), position)
} else {
mCheckedIdStates!!.remove(mAdapter!!.getItemId(position))
}
}
if (oldValue != value) {
if (value) {
checkedItemCount++
} else {
checkedItemCount--
}
}
if (mChoiceMode == CHOICE_MODE_MULTIPLE_CUSTOM) {
val id = mAdapter!!.getItemId(position)
mCustomChoiceListener!!.onItemCheckedStateChanged(this, position, id, value)
}
} else {
val updateIds = mCheckedIdStates != null && mAdapter!!.hasStableIds()
// Clear all values if we're checking something, or unchecking the currently
// selected item
if (value || isItemChecked(position)) {
mCheckStates!!.clear()
if (updateIds) {
mCheckedIdStates!!.clear()
}
}
// this may end up selecting the value we just cleared but this way
// we ensure length of mCheckStates is 1, a fact getCheckedItemPosition relies on
if (value) {
mCheckStates!!.put(position, true)
if (updateIds) {
mCheckedIdStates!!.put(mAdapter!!.getItemId(position), position)
}
checkedItemCount = 1
} else if (mCheckStates!!.size() == 0 || !mCheckStates!!.valueAt(0)) {
checkedItemCount = 0
}
}
updateOnScreenCheckedViews()
}
/**
* Defines the choice behavior for the List. By default, Lists do not have any choice behavior
* ([.CHOICE_MODE_NONE]). By setting the choiceMode to [.CHOICE_MODE_SINGLE], the
* List allows up to one item to be in a chosen state. By setting the choiceMode to
* [.CHOICE_MODE_MULTIPLE], the list allows any number of items to be chosen.
*
* @param choiceMode One of [.CHOICE_MODE_NONE], [.CHOICE_MODE_SINGLE], or
* [.CHOICE_MODE_MULTIPLE]
*/
fun setChoiceMode(choiceMode: Int) {
mChoiceMode = choiceMode
if (mChoiceMode != CHOICE_MODE_NONE) {
if (mCheckStates == null) {
mCheckStates = SparseBooleanArray(0)
}
if (mCheckedIdStates == null && mAdapter != null && mAdapter!!.hasStableIds()) {
mCheckedIdStates = LongSparseArray(0)
}
if (mChoiceMode == CHOICE_MODE_MULTIPLE_CUSTOM) {
if (mTempCheckStates == null) {
mTempCheckStates = SparseBooleanArray(0)
}
clearChoices()
}
}
}
fun setCustomCheckedListener(listener: CustomChoiceListener?) {
mCustomChoiceListener = listener
}
/**
* Perform a quick, in-place update of the checked or activated state
* on all visible item views. This should only be called when a valid
* choice mode is active.
*/
private fun updateOnScreenCheckedViews() {
val count = childCount
for (i in 0 until count) {
val child = getChildAt(i)
val position = getChildAdapterPosition(child)
setViewChecked(child, mCheckStates!![position])
}
}
init {
val scale = context.resources.displayMetrics.density
// g (m/s^2)
// inch/meter
// A context-specific coefficient adjusted to physical values.
// look and feel tuning
pageScrollThreshold = scale * 80
}
override fun onSaveInstanceState(): Parcelable {
val ss = SavedState(super.onSaveInstanceState())
ss.choiceMode = mChoiceMode
ss.customChoice = isInCustomChoice
ss.checkedItemCount = checkedItemCount
ss.checkState = mCheckStates
ss.checkIdState = mCheckedIdStates
return ss
}
override fun onRestoreInstanceState(state: Parcelable) {
val ss = state as SavedState
super.onRestoreInstanceState(ss.superState)
setChoiceMode(ss.choiceMode)
isInCustomChoice = ss.customChoice
checkedItemCount = ss.checkedItemCount
if (ss.checkState != null) {
mCheckStates = ss.checkState
}
if (ss.checkIdState != null) {
mCheckedIdStates = ss.checkIdState
}
updateOnScreenCheckedViews()
}
/**
* Custom checked
*/
interface CustomChoiceListener {
fun onIntoCustomChoice(view: EasyRecyclerView)
fun onOutOfCustomChoice(view: EasyRecyclerView)
fun onItemCheckedStateChanged(
view: EasyRecyclerView,
position: Int,
id: Long,
checked: Boolean,
)
}
/**
* This saved state class is a Parcelable and should not extend
* [android.view.View.BaseSavedState] nor [android.view.AbsSavedState]
* because its super class AbsSavedState's constructor
* currently passes null
* as a class loader to read its superstate from Parcelable.
* This causes [android.os.BadParcelableException] when restoring saved states.
*
*
* The super class "RecyclerView" is a part of the support library,
* and restoring its saved state requires the class loader that loaded the RecyclerView.
* It seems that the class loader is not required when restoring from RecyclerView itself,
* but it is required when restoring from RecyclerView's subclasses.
*/
internal open class SavedState : Parcelable {
var choiceMode = 0
var customChoice = false
var checkedItemCount = 0
var checkState: SparseBooleanArray? = null
var checkIdState: LongSparseArray<Int>? = null
// This keeps the parent(RecyclerView)'s state
var superState: Parcelable?
constructor() {
superState = null
}
/**
* Constructor called from [.onSaveInstanceState]
*/
constructor(superState: Parcelable?) {
this.superState = if (superState !== EMPTY_STATE) superState else null
}
/**
* Constructor called from [.CREATOR]
*/
private constructor(`in`: Parcel) {
// Parcel 'in' has its parent(RecyclerView)'s saved state.
// To restore it, class loader that loaded RecyclerView is required.
val superState =
readParcelable(`in`, RecyclerView::class.java.classLoader, Parcelable::class.java)
this.superState = superState ?: EMPTY_STATE
choiceMode = `in`.readInt()
customChoice = `in`.readInt() != 0
checkedItemCount = `in`.readInt()
checkState = `in`.readSparseBooleanArray()
val n = `in`.readInt()
if (n > 0) {
checkIdState = LongSparseArray()
for (i in 0 until n) {
val key = `in`.readLong()
val value = `in`.readInt()
checkIdState!!.put(key, value)
}
}
}
override fun describeContents(): Int {
return 0
}
override fun writeToParcel(out: Parcel, flags: Int) {
out.writeParcelable(superState, flags)
out.writeInt(choiceMode)
out.writeInt(customChoice.compareTo(false))
out.writeInt(checkedItemCount)
out.writeSparseBooleanArray(checkState)
val n = if (checkIdState != null) checkIdState!!.size() else 0
out.writeInt(n)
for (i in 0 until n) {
out.writeLong(checkIdState!!.keyAt(i))
out.writeInt(checkIdState!!.valueAt(i))
}
}
companion object CREATOR : Parcelable.Creator<SavedState> {
private val EMPTY_STATE = SavedState()
override fun createFromParcel(parcel: Parcel): SavedState {
return SavedState(parcel)
}
override fun newArray(size: Int): Array<SavedState?> {
return arrayOfNulls(size)
}
}
}
companion object {
const val CHOICE_MODE_NONE = 0
const val CHOICE_MODE_MULTIPLE_CUSTOM = 1
fun setViewChecked(view: View, checked: Boolean) {
if (view is Checkable) {
(view as Checkable).isChecked = checked
} else {
view.isActivated = checked
}
}
}
}
@@ -0,0 +1,125 @@
package com.hippo.ehviewer.ui.legacy
import android.content.Context
import android.os.Parcelable
import android.util.AttributeSet
import android.view.View
import android.widget.Checkable
import androidx.core.view.children
import androidx.recyclerview.widget.RecyclerView
import kotlinx.parcelize.Parcelize
class SelectableGalleryInfoRecyclerView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0,
) : RecyclerView(context, attrs, defStyle) {
private var customChoiceListener: CustomChoiceListener? = null
private var mOutOfCustomChoiceModing = false
var isInCustomChoice = false
private set
val checkedItemCount
get() = checkedGid.size
lateinit var gidGetter: (Int) -> Long?
private var checkedGid = mutableSetOf<Long>()
private fun checkChild(child: View) {
val position = getChildAdapterPosition(child)
val gid = gidGetter(position) ?: return
setViewChecked(child, gid in checkedGid)
}
override fun onChildAttachedToWindow(child: View) {
super.onChildAttachedToWindow(child)
checkChild(child)
}
val checkedItemGid: Set<Long>
get() = checkedGid
fun intoCustomChoiceMode() {
if (!isInCustomChoice) {
isInCustomChoice = true
customChoiceListener?.onIntoCustomChoice(this)
}
}
fun outOfCustomChoiceMode() {
if (isInCustomChoice && !mOutOfCustomChoiceModing) {
mOutOfCustomChoiceModing = true
clearChoices()
isInCustomChoice = false
customChoiceListener?.onOutOfCustomChoice(this)
mOutOfCustomChoiceModing = false
}
}
private fun clearChoices() {
checkedGid.clear()
updateOnScreenCheckedViews()
}
fun checkAll() {
check(isInCustomChoice) { "Call intoCheckMode first" }
// Foreach checked
// Notify customChoiceListener!!.onItemCheckedStateChanged(this)
updateOnScreenCheckedViews()
}
fun toggleItemChecked(position: Int) {
check(isInCustomChoice) { "Call intoCheckMode first" }
val gid = gidGetter(position) ?: return
if (gid in checkedGid) {
checkedGid.remove(gid)
} else {
checkedGid.add(gid)
}
customChoiceListener?.onItemCheckedStateChanged(this)
updateOnScreenCheckedViews()
}
fun setCustomCheckedListener(listener: CustomChoiceListener?) {
customChoiceListener = listener
}
private fun updateOnScreenCheckedViews() {
children.forEach {
checkChild(it)
}
}
override fun onSaveInstanceState() = SavedState(
isInCustomChoice,
checkedGid,
super.onSaveInstanceState(),
)
override fun onRestoreInstanceState(state: Parcelable) {
val ss = state as SavedState
super.onRestoreInstanceState(ss.superState)
isInCustomChoice = ss.customChoice
checkedGid = ss.checkedGid
updateOnScreenCheckedViews()
}
interface CustomChoiceListener {
fun onIntoCustomChoice(view: SelectableGalleryInfoRecyclerView)
fun onOutOfCustomChoice(view: SelectableGalleryInfoRecyclerView)
fun onItemCheckedStateChanged(view: SelectableGalleryInfoRecyclerView)
}
@Parcelize
class SavedState(
val customChoice: Boolean,
val checkedGid: MutableSet<Long>,
val superState: Parcelable?,
) : Parcelable
}
private fun setViewChecked(view: View, checked: Boolean) {
if (view is Checkable) {
(view as Checkable).isChecked = checked
} else {
view.isActivated = checked
}
}
@@ -79,8 +79,6 @@ import com.hippo.ehviewer.spider.putToDownloadDir
import com.hippo.ehviewer.ui.legacy.AutoStaggeredGridLayoutManager
import com.hippo.ehviewer.ui.legacy.BaseDialogBuilder
import com.hippo.ehviewer.ui.legacy.CheckBoxDialogBuilder
import com.hippo.ehviewer.ui.legacy.EasyRecyclerView
import com.hippo.ehviewer.ui.legacy.EasyRecyclerView.CustomChoiceListener
import com.hippo.ehviewer.ui.legacy.EditTextDialogBuilder
import com.hippo.ehviewer.ui.legacy.FabLayout
import com.hippo.ehviewer.ui.legacy.FabLayout.OnClickFabListener
@@ -88,6 +86,8 @@ import com.hippo.ehviewer.ui.legacy.FabLayout.OnExpandListener
import com.hippo.ehviewer.ui.legacy.FastScroller.OnDragHandlerListener
import com.hippo.ehviewer.ui.legacy.HandlerDrawable
import com.hippo.ehviewer.ui.legacy.STRATEGY_MIN_SIZE
import com.hippo.ehviewer.ui.legacy.SelectableGalleryInfoRecyclerView
import com.hippo.ehviewer.ui.legacy.SelectableGalleryInfoRecyclerView.CustomChoiceListener
import com.hippo.ehviewer.ui.legacy.ViewTransition
import com.hippo.ehviewer.ui.main.requestOf
import com.hippo.ehviewer.ui.navToReader
@@ -277,7 +277,7 @@ class DownloadsScene :
recyclerView.layoutManager = layoutManager
recyclerView.clipToPadding = false
recyclerView.clipChildren = false
recyclerView.setChoiceMode(EasyRecyclerView.CHOICE_MODE_MULTIPLE_CUSTOM)
recyclerView.gidGetter = { mList?.get(it)?.gid }
recyclerView.setCustomCheckedListener(DownloadChoiceListener())
// Cancel change animation
val itemAnimator = recyclerView.itemAnimator
@@ -566,16 +566,12 @@ class DownloadsScene :
if (collectDownloadInfo) {
downloadInfoList = LinkedList()
}
val stateArray = binding.recyclerView.checkedItemPositions!!
for (i in 0 until stateArray.size()) {
if (stateArray.valueAt(i)) {
val info = list[stateArray.keyAt(i)]
if (collectDownloadInfo) {
downloadInfoList!!.add(info)
}
if (collectGid) {
gidList!!.add(info.gid)
}
binding.recyclerView.checkedItemGid.mapNotNull { gid -> list.find { it.gid == gid } }.forEach {
if (collectDownloadInfo) {
downloadInfoList!!.add(it)
}
if (collectGid) {
gidList!!.add(it.gid)
}
}
when (position) {
@@ -1050,26 +1046,21 @@ class DownloadsScene :
}
private inner class DownloadChoiceListener : CustomChoiceListener {
override fun onIntoCustomChoice(view: EasyRecyclerView) {
override fun onIntoCustomChoice(view: SelectableGalleryInfoRecyclerView) {
binding.fabLayout.isExpanded = true
// Lock drawer
setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, GravityCompat.START)
setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, GravityCompat.END)
}
override fun onOutOfCustomChoice(view: EasyRecyclerView) {
override fun onOutOfCustomChoice(view: SelectableGalleryInfoRecyclerView) {
binding.fabLayout.isExpanded = false
// Unlock drawer
setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, GravityCompat.START)
setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, GravityCompat.END)
}
override fun onItemCheckedStateChanged(
view: EasyRecyclerView,
position: Int,
id: Long,
checked: Boolean,
) {
override fun onItemCheckedStateChanged(view: SelectableGalleryInfoRecyclerView) {
if (view.checkedItemCount == 0) {
view.outOfCustomChoiceMode()
}
@@ -37,7 +37,6 @@ import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.res.stringResource
import androidx.core.content.ContextCompat
import androidx.core.os.bundleOf
import androidx.core.util.valueIterator
import androidx.core.view.GravityCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsAnimationCompat
@@ -72,12 +71,12 @@ import com.hippo.ehviewer.databinding.SceneFavoritesBinding
import com.hippo.ehviewer.ui.CommonOperations
import com.hippo.ehviewer.ui.legacy.AddDeleteDrawable
import com.hippo.ehviewer.ui.legacy.BaseDialogBuilder
import com.hippo.ehviewer.ui.legacy.EasyRecyclerView
import com.hippo.ehviewer.ui.legacy.EasyRecyclerView.CustomChoiceListener
import com.hippo.ehviewer.ui.legacy.FabLayout
import com.hippo.ehviewer.ui.legacy.FabLayout.OnClickFabListener
import com.hippo.ehviewer.ui.legacy.FastScroller.OnDragHandlerListener
import com.hippo.ehviewer.ui.legacy.HandlerDrawable
import com.hippo.ehviewer.ui.legacy.SelectableGalleryInfoRecyclerView
import com.hippo.ehviewer.ui.legacy.SelectableGalleryInfoRecyclerView.CustomChoiceListener
import com.hippo.ehviewer.ui.legacy.ViewTransition
import com.hippo.ehviewer.ui.legacy.WindowInsetsAnimationHelper
import com.hippo.ehviewer.ui.setMD3Content
@@ -354,11 +353,11 @@ class FavoritesScene : SearchBarScene() {
}
}
}
gidGetter = { adapter.peek(it)?.gid }
}
switchFav(Settings.recentFavCat)
setChoiceMode(EasyRecyclerView.CHOICE_MODE_MULTIPLE_CUSTOM)
setCustomCheckedListener(object : CustomChoiceListener {
override fun onIntoCustomChoice(view: EasyRecyclerView) {
override fun onIntoCustomChoice(view: SelectableGalleryInfoRecyclerView) {
showSelectionFab()
binding.fabLayout.setAutoCancel(false)
// Delay expanding action to make layout work fine
@@ -369,7 +368,7 @@ class FavoritesScene : SearchBarScene() {
setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, GravityCompat.END)
}
override fun onOutOfCustomChoice(view: EasyRecyclerView) {
override fun onOutOfCustomChoice(view: SelectableGalleryInfoRecyclerView) {
showNormalFab()
binding.fabLayout.setAutoCancel(true)
binding.fabLayout.isExpanded = false
@@ -379,7 +378,7 @@ class FavoritesScene : SearchBarScene() {
setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, GravityCompat.END)
}
override fun onItemCheckedStateChanged(view: EasyRecyclerView, position: Int, id: Long, checked: Boolean) {
override fun onItemCheckedStateChanged(view: SelectableGalleryInfoRecyclerView) {
if (view.checkedItemCount == 0) {
view.outOfCustomChoiceMode()
}
@@ -470,9 +469,8 @@ class FavoritesScene : SearchBarScene() {
}
private fun takeCheckedInfo() = run {
val stateArray = binding.recyclerView.checkedItemPositions!!
stateArray.valueIterator().asSequence().withIndex().filter { it.value }
.mapNotNull { mAdapter?.peek(stateArray.keyAt(it.index)) }.toList()
val snapshot = mAdapter?.snapshot()?.items
binding.recyclerView.checkedItemGid.mapNotNull { gid -> snapshot?.find { it.gid == gid } }
}.also { binding.recyclerView.outOfCustomChoiceMode() }
private fun checkedSize() = binding.recyclerView.checkedItemCount
+1 -1
View File
@@ -23,7 +23,7 @@
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<com.hippo.ehviewer.ui.legacy.EasyRecyclerView
<com.hippo.ehviewer.ui.legacy.SelectableGalleryInfoRecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
+1 -1
View File
@@ -42,7 +42,7 @@
app:fitsSystemWindowsInsets="top"
app:layout_behavior="@string/searchbar_scrolling_view_behavior">
<com.hippo.ehviewer.ui.legacy.EasyRecyclerView
<com.hippo.ehviewer.ui.legacy.SelectableGalleryInfoRecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"