多层目录 #138
This commit is contained in:
@@ -108,7 +108,7 @@ abstract class DiffRecyclerAdapter<ITEM, VB : ViewBinding>(protected val context
|
||||
|
||||
fun isNotEmpty() = asyncListDiffer.currentList.isNotEmpty()
|
||||
|
||||
fun getItem(position: Int): ITEM? = asyncListDiffer.currentList.getOrNull(position)
|
||||
open fun getItem(position: Int): ITEM? = asyncListDiffer.currentList.getOrNull(position)
|
||||
|
||||
fun getItems(): List<ITEM> = asyncListDiffer.currentList
|
||||
|
||||
@@ -117,7 +117,7 @@ abstract class DiffRecyclerAdapter<ITEM, VB : ViewBinding>(protected val context
|
||||
*/
|
||||
protected open fun getSpanSize(viewType: Int, position: Int) = 1
|
||||
|
||||
final override fun getItemCount() = getItems().size
|
||||
override fun getItemCount() = getItems().size
|
||||
|
||||
final override fun getItemViewType(position: Int): Int {
|
||||
return 0
|
||||
|
||||
@@ -38,6 +38,8 @@ class ChapterListAdapter(
|
||||
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
private var upDisplayTileJob: Job? = null
|
||||
private val collapsedVolumes = mutableSetOf<Int>() // 保存折叠的卷index
|
||||
private var visibleItems = mutableListOf<BookChapter>() // 当前显示
|
||||
|
||||
override val diffItemCallback: DiffUtil.ItemCallback<BookChapter>
|
||||
get() = object : DiffUtil.ItemCallback<BookChapter>() {
|
||||
@@ -59,6 +61,7 @@ class ChapterListAdapter(
|
||||
|
||||
override fun onCurrentListChanged() {
|
||||
super.onCurrentListChanged()
|
||||
rebuildVisibleItems()
|
||||
callback.onListChanged()
|
||||
}
|
||||
|
||||
@@ -169,9 +172,71 @@ class ChapterListAdapter(
|
||||
callback.onSelectionModeChanged(isInSelectionMode())
|
||||
}
|
||||
|
||||
private fun rebuildVisibleItems() {
|
||||
val all = getItems()
|
||||
visibleItems.clear()
|
||||
var currentVolumeCollapsed = false
|
||||
for (item in all) {
|
||||
if (item.isVolume) {
|
||||
visibleItems.add(item)
|
||||
currentVolumeCollapsed = collapsedVolumes.contains(item.index)
|
||||
} else if (!currentVolumeCollapsed) {
|
||||
visibleItems.add(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun toggleVolume(volume: BookChapter) {
|
||||
if (!volume.isVolume) return
|
||||
|
||||
val all = getItems()
|
||||
val startIndex = all.indexOf(volume)
|
||||
if (startIndex == -1) return
|
||||
|
||||
val currentPos = visibleItems.indexOf(volume)
|
||||
if (currentPos == -1) return
|
||||
|
||||
if (collapsedVolumes.contains(volume.index)) {
|
||||
collapsedVolumes.remove(volume.index)
|
||||
|
||||
val toAdd = mutableListOf<BookChapter>()
|
||||
for (i in startIndex + 1 until all.size) {
|
||||
val next = all[i]
|
||||
if (next.isVolume) break
|
||||
toAdd.add(next)
|
||||
}
|
||||
|
||||
val insertPos = currentPos + 1
|
||||
visibleItems.addAll(insertPos, toAdd)
|
||||
|
||||
notifyItemRangeInserted(insertPos, toAdd.size)
|
||||
notifyItemChanged(currentPos)
|
||||
|
||||
} else {
|
||||
collapsedVolumes.add(volume.index)
|
||||
val toRemove = mutableListOf<BookChapter>()
|
||||
for (i in startIndex + 1 until all.size) {
|
||||
val next = all[i]
|
||||
if (next.isVolume) break
|
||||
toRemove.add(next)
|
||||
}
|
||||
if (toRemove.isNotEmpty()) {
|
||||
val removeStart = currentPos + 1
|
||||
visibleItems.removeAll(toRemove)
|
||||
notifyItemRangeRemoved(removeStart, toRemove.size)
|
||||
notifyItemChanged(currentPos)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDisplayTitle(chapter: BookChapter): String =
|
||||
displayTitleMap[chapter.url] ?: chapter.title
|
||||
|
||||
override fun getItemCount(): Int = visibleItems.size
|
||||
|
||||
override fun getItem(position: Int): BookChapter? =
|
||||
visibleItems.getOrNull(position)
|
||||
|
||||
override fun getViewBinding(parent: ViewGroup): ItemChapterListBinding =
|
||||
ItemChapterListBinding.inflate(inflater, parent, false)
|
||||
|
||||
@@ -182,8 +247,9 @@ class ChapterListAdapter(
|
||||
payloads: MutableList<Any>
|
||||
) {
|
||||
val isDur = callback.durChapterIndex() == item.index
|
||||
val cached =
|
||||
callback.isLocalBook || item.isVolume || cacheFileNames.contains(item.getFileName())
|
||||
val cached = callback.isLocalBook || item.isVolume || cacheFileNames.contains(item.getFileName())
|
||||
val isSelected = selectedIndices.contains(item.index)
|
||||
val isCollapsed = collapsedVolumes.contains(item.index)
|
||||
|
||||
binding.run {
|
||||
if (payloads.isEmpty()) {
|
||||
@@ -204,31 +270,40 @@ class ChapterListAdapter(
|
||||
if (item.isVip && !item.isPay) ivLocked.visible() else ivLocked.gone()
|
||||
|
||||
upHasCache(binding, cached)
|
||||
|
||||
} else {
|
||||
tvChapterName.text = getDisplayTitle(item)
|
||||
upHasCache(binding, cached)
|
||||
}
|
||||
|
||||
if (selectedIndices.contains(item.index)) {
|
||||
ivVolume.gone()
|
||||
tvChapterItem.setBackgroundColor(context.themeColor(com.google.android.material.R.attr.colorSurfaceContainerHighest))
|
||||
} else {
|
||||
if (item.isVolume) {
|
||||
when {
|
||||
item.isVolume -> {
|
||||
ivVolume.visible()
|
||||
if (isCollapsed) ivColl.visible()
|
||||
else ivColl.gone()
|
||||
tvChapterName.textSize = 12f
|
||||
tvChapterName.setTextColor(context.themeColor(com.google.android.material.R.attr.colorTertiary))
|
||||
tvChapterItem.setBackgroundColor(context.themeColor(com.google.android.material.R.attr.colorSurface))
|
||||
} else {
|
||||
ivVolume.gone()
|
||||
if (isDur) {
|
||||
tvChapterName.setTextColor(context.themeColor(androidx.appcompat.R.attr.colorPrimary))
|
||||
tvChapterItem.setBackgroundColor(context.themeColor(com.google.android.material.R.attr.colorSurfaceContainer))
|
||||
} else {
|
||||
tvChapterName.setTextColor(context.themeColor(com.google.android.material.R.attr.colorOnSurface))
|
||||
tvChapterItem.setBackgroundColor(context.themeColor(com.google.android.material.R.attr.colorSurface))
|
||||
}
|
||||
}
|
||||
|
||||
isDur -> {
|
||||
ivColl.gone()
|
||||
ivVolume.gone()
|
||||
tvChapterName.setTextColor(context.themeColor(androidx.appcompat.R.attr.colorPrimary))
|
||||
tvChapterItem.setBackgroundColor(context.themeColor(com.google.android.material.R.attr.colorSurfaceContainer))
|
||||
}
|
||||
|
||||
else -> {
|
||||
ivColl.gone()
|
||||
ivVolume.gone()
|
||||
tvChapterName.setTextColor(context.themeColor(com.google.android.material.R.attr.colorOnSurface))
|
||||
tvChapterItem.setBackgroundColor(context.themeColor(com.google.android.material.R.attr.colorSurface))
|
||||
}
|
||||
}
|
||||
|
||||
if (isSelected) {
|
||||
tvChapterItem.setBackgroundColor(
|
||||
context.themeColor(com.google.android.material.R.attr.colorSurfaceContainerHighest)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -240,6 +315,11 @@ class ChapterListAdapter(
|
||||
if (pos == RecyclerView.NO_POSITION) return@setOnClickListener
|
||||
val item = getItem(pos) ?: return@setOnClickListener
|
||||
|
||||
if (item.isVolume) {
|
||||
toggleVolume(item)
|
||||
return@setOnClickListener
|
||||
}
|
||||
|
||||
if (isInSelectionMode()) {
|
||||
toggleSelection(item, pos)
|
||||
} else {
|
||||
|
||||
@@ -38,12 +38,12 @@
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_chap"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/iv_checked"
|
||||
app:layout_constraintEnd_toStartOf="@id/iv_Coll"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/ll_info">
|
||||
|
||||
@@ -85,6 +85,23 @@
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_word_count" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/iv_Coll"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:strokeWidth="0dp"
|
||||
app:cardBackgroundColor="?attr/colorSurfaceContainerHighest"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/iv_checked">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="visible"
|
||||
android:src="@drawable/ic_arrow_drop_down" />
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_checked"
|
||||
android:layout_width="24dp"
|
||||
|
||||
Reference in New Issue
Block a user