增加一个新的紧凑列表布局

This commit is contained in:
HapeLee
2025-10-09 02:13:36 +08:00
parent 8a7936d6fa
commit cc4b9c31d2
14 changed files with 724 additions and 124 deletions
@@ -36,6 +36,7 @@ class BookshelfConfigBottomSheet : BaseBottomSheetDialogFragment(R.layout.dialog
val isGrid = bookshelfLayout == 1
val isGridCompact = bookshelfLayout == 2
val isGridCover = bookshelfLayout == 3
val isListCompact = bookshelfLayout == 4
val columnCount = requireContext().bookshelfLayoutGrid.takeIf { it > 0 } ?: 1
@@ -76,13 +77,17 @@ class BookshelfConfigBottomSheet : BaseBottomSheetDialogFragment(R.layout.dialog
swShowBookshelfFastScroller.isChecked = AppConfig.showBookshelfFastScroller
chipList.isChecked = isList
chipListCompact.isChecked = isListCompact
chipGrid.isChecked = isGrid
chipGridCompact.isChecked = isGridCompact
chipGridCover.isChecked = isGridCover
sliderText.isVisible = isGrid || isGridCompact || isGridCover
sliderGridCount.isVisible = isGrid || isGridCompact || isGridCover
val showSlider = isGrid || isGridCompact || isGridCover
sliderText.isVisible = showSlider
sliderGridCount.isVisible = showSlider
sliderGridCount.value = columnCount.toFloat()
when (AppConfig.bookshelfSortOrder) {
0 -> binding.chipGroupOrder.check(binding.chipAsc.id)
1 -> binding.chipGroupOrder.check(binding.chipDesc.id)
@@ -90,10 +95,11 @@ class BookshelfConfigBottomSheet : BaseBottomSheetDialogFragment(R.layout.dialog
chipGroupLayout.setOnCheckedStateChangeListener { _, checkedIds ->
val checkedId = checkedIds.firstOrNull()
val showSlider =
checkedId == R.id.chip_grid || checkedId == R.id.chip_grid_compact || checkedId == R.id.chip_grid_cover
sliderText.isVisible = showSlider
val showSlider = checkedId == R.id.chip_grid ||
checkedId == R.id.chip_grid_compact ||
checkedId == R.id.chip_grid_cover
TransitionManager.beginDelayedTransition(root)
sliderText.isVisible = showSlider
sliderGridCount.isVisible = showSlider
}
@@ -136,6 +142,7 @@ class BookshelfConfigBottomSheet : BaseBottomSheetDialogFragment(R.layout.dialog
chipGrid.isChecked -> 1
chipGridCompact.isChecked -> 2
chipGridCover.isChecked -> 3
chipListCompact.isChecked -> 4
else -> 0
}
@@ -149,7 +156,7 @@ class BookshelfConfigBottomSheet : BaseBottomSheetDialogFragment(R.layout.dialog
AppConfig.bookshelfLayoutGridPortrait = selectedColumn
}
if (newLayout == 0) {
if (newLayout == 0 || newLayout == 4) {
activityViewModel.booksGridRecycledViewPool.clear()
} else {
activityViewModel.booksListRecycledViewPool.clear()
@@ -39,6 +39,7 @@ import io.legato.kazusa.ui.main.bookshelf.books.styleDefalut.BooksAdapterGrid
import io.legato.kazusa.ui.main.bookshelf.books.styleDefalut.BooksAdapterGridCompact
import io.legato.kazusa.ui.main.bookshelf.books.styleDefalut.BooksAdapterGridCover
import io.legato.kazusa.ui.main.bookshelf.books.styleDefalut.BooksAdapterList
import io.legato.kazusa.ui.main.bookshelf.books.styleDefalut.BooksAdapterListCompact
import io.legato.kazusa.utils.bookshelfLayoutGrid
import io.legato.kazusa.utils.bookshelfLayoutMode
import io.legato.kazusa.utils.cnCompare
@@ -92,9 +93,13 @@ class BooksFragment() : BaseFragment(R.layout.fragment_books),
BooksAdapterGridCompact(requireContext(), this)
}
else -> {
3 -> {
BooksAdapterGridCover(requireContext(), this)
}
else -> {
BooksAdapterListCompact(requireContext(), this, this, viewLifecycleOwner.lifecycle)
}
}
}
private var booksFlowJob: Job? = null
@@ -127,7 +132,7 @@ class BooksFragment() : BaseFragment(R.layout.fragment_books),
binding.refreshLayout.isRefreshing = false
activityViewModel.upToc(booksAdapter.getItems())
}
if (bookshelfLayoutMode == 0) {
if (bookshelfLayoutMode == 0 ||bookshelfLayoutMode == 4) {
binding.rvBookshelf.layoutManager = LinearLayoutManager(context)
binding.rvBookshelf.setRecycledViewPool(activityViewModel.booksListRecycledViewPool)
} else {
@@ -232,7 +237,7 @@ class BooksFragment() : BaseFragment(R.layout.fragment_books),
private fun startLastUpdateTimeJob() {
upLastUpdateTimeJob?.cancel()
if (!AppConfig.showLastUpdateTime || bookshelfLayoutMode != 0) {
if (!AppConfig.showLastUpdateTime || bookshelfLayoutMode != 0 ||bookshelfLayoutMode != 4) {
return
}
upLastUpdateTimeJob = lifecycleScope.launch {
@@ -36,6 +36,7 @@ import io.legato.kazusa.ui.main.bookshelf.books.styleFold.BooksAdapterGrid
import io.legato.kazusa.ui.main.bookshelf.books.styleFold.BooksAdapterGridCompact
import io.legato.kazusa.ui.main.bookshelf.books.styleFold.BooksAdapterGridCover
import io.legato.kazusa.ui.main.bookshelf.books.styleFold.BooksAdapterList
import io.legato.kazusa.ui.main.bookshelf.books.styleFold.BooksAdapterListCompact
import io.legato.kazusa.utils.bookshelfLayoutGrid
import io.legato.kazusa.utils.bookshelfLayoutMode
import io.legato.kazusa.utils.cnCompare
@@ -85,9 +86,13 @@ class BookshelfFragment2() : BaseBookshelfFragment(R.layout.fragment_bookshelf2)
BooksAdapterGridCompact(requireContext(), this)
}
else -> {
3 -> {
BooksAdapterGridCover(requireContext(), this)
}
else -> {
BooksAdapterListCompact(requireContext(), this)
}
}
}
@@ -111,7 +116,7 @@ class BookshelfFragment2() : BaseBookshelfFragment(R.layout.fragment_bookshelf2)
binding.refreshLayout.isRefreshing = false
activityViewModel.upToc(books)
}
if (bookshelfLayoutMode == 0) {
if (bookshelfLayoutMode == 0 || bookshelfLayoutMode == 4) {
binding.rvBookshelf.layoutManager = LinearLayoutManager(context)
} else {
binding.rvBookshelf.layoutManager = GridLayoutManager(context, bookshelfLayoutGrid)
@@ -0,0 +1,116 @@
package io.legato.kazusa.ui.main.bookshelf.books.styleDefalut
import android.content.Context
import android.os.Bundle
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import io.legato.kazusa.R
import io.legato.kazusa.base.adapter.ItemViewHolder
import io.legato.kazusa.data.entities.Book
import io.legato.kazusa.databinding.ItemBookshelfListCompactBinding
import io.legato.kazusa.help.book.isLocal
import io.legato.kazusa.help.config.AppConfig
import io.legato.kazusa.utils.toTimeAgo
import splitties.views.onLongClick
class BooksAdapterListCompact(
context: Context,
private val fragment: Fragment,
private val callBack: CallBack,
private val lifecycle: Lifecycle
) : BaseBooksAdapter<ItemBookshelfListCompactBinding>(context) {
override fun getViewBinding(parent: ViewGroup): ItemBookshelfListCompactBinding {
return ItemBookshelfListCompactBinding.inflate(inflater, parent, false)
}
override fun convert(
holder: ItemViewHolder,
binding: ItemBookshelfListCompactBinding,
item: Book,
payloads: MutableList<Any>
) = binding.run {
binding.cdCover.transitionName = "book_${item.bookUrl}"
if (payloads.isEmpty()) {
tvName.text = item.name
tvAuthor.text =
context.getString(
R.string.author_read,
item.author,
(item.totalChapterNum - item.durChapterIndex).coerceAtLeast(0)
)
tvLast.text = item.latestChapterTitle
ivCover.load(item.getDisplayCover(), item.name, item.author, false, item.origin)
upRefresh(binding, item)
upLastUpdateTime(binding, item)
} else {
for (i in payloads.indices) {
val bundle = payloads[i] as Bundle
bundle.keySet().forEach {
when (it) {
"name" -> tvName.text = item.name
"author" -> tvAuthor.text = item.author
"last" -> tvLast.text = item.latestChapterTitle
"cover" -> ivCover.load(
item.getDisplayCover(),
item.name,
item.author,
false,
item.origin,
fragment,
lifecycle
)
"refresh" -> upRefresh(binding, item)
"lastUpdateTime" -> upLastUpdateTime(binding, item)
}
}
}
}
}
private fun upRefresh(binding: ItemBookshelfListCompactBinding, item: Book) {
if (!item.isLocal && callBack.isUpdate(item.bookUrl)) {
binding.tvUnread.isVisible = false
binding.rlLoading.isVisible = true
} else {
binding.rlLoading.isVisible = false
if (AppConfig.showUnread) {
//binding.tvUnread.setHighlight(item.lastCheckCount > 0)
binding.tvUnread.isVisible = true
binding.tvUnread.text = item.getUnreadChapterNum().toString()
} else {
binding.tvUnread.isVisible = false
}
}
}
private fun upLastUpdateTime(binding: ItemBookshelfListCompactBinding, item: Book) {
if (AppConfig.showLastUpdateTime && !item.isLocal) {
val time = item.latestChapterTime.toTimeAgo()
if (binding.tvLastUpdateTime.text != time) {
binding.tvLastUpdateTime.text = time
}
} else {
binding.tvLastUpdateTime.text = ""
}
}
override fun registerListener(holder: ItemViewHolder, binding: ItemBookshelfListCompactBinding) {
holder.itemView.apply {
binding.cvContent.setOnClickListener {
getItem(holder.layoutPosition)?.let {
callBack.open(it, binding.cdCover)
}
}
binding.cvContent.onLongClick {
getItem(holder.layoutPosition)?.let {
callBack.openBookInfo(it, binding.cdCover)
}
}
}
}
}
@@ -65,9 +65,9 @@ class BooksAdapterList(context: Context, callBack: CallBack) :
tvLast.text = item.latestChapterTitle
ivCover.load(item.getDisplayCover(), item.name, item.author, false, item.origin)
cdUnread.visible()
ivAuthor.visible()
ivLast.visible()
ivRead.visible()
// ivAuthor.visible()
// ivLast.visible()
// ivRead.visible()
upRefresh(this, item)
upLastUpdateTime(binding, item)
}
@@ -0,0 +1,194 @@
package io.legato.kazusa.ui.main.bookshelf.books.styleFold
import android.content.Context
import android.os.Bundle
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
import io.legato.kazusa.R
import io.legato.kazusa.data.entities.Book
import io.legato.kazusa.data.entities.BookGroup
import io.legato.kazusa.databinding.ItemBookshelfListCompactBinding
import io.legato.kazusa.databinding.ItemBookshelfListCompactGroupBinding
import io.legato.kazusa.help.book.isLocal
import io.legato.kazusa.help.config.AppConfig
import io.legato.kazusa.utils.gone
import io.legato.kazusa.utils.toTimeAgo
import io.legato.kazusa.utils.visible
import splitties.views.onLongClick
@Suppress("UNUSED_PARAMETER")
class BooksAdapterListCompact(context: Context, callBack: CallBack) :
BaseBooksAdapter<RecyclerView.ViewHolder>(context, callBack) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
1 -> GroupViewHolder(ItemBookshelfListCompactGroupBinding.inflate(inflater, parent, false))
else -> BookViewHolder(ItemBookshelfListCompactBinding.inflate(inflater, parent, false))
}
}
override fun onBindViewHolder(
holder: RecyclerView.ViewHolder,
position: Int,
payloads: MutableList<Any>
) {
when (holder) {
is BookViewHolder -> (getItem(position) as? Book)?.let {
holder.registerListener(it)
holder.onBind(it, payloads)
}
is GroupViewHolder -> (getItem(position) as? BookGroup)?.let {
holder.registerListener(it)
holder.onBind(it, payloads)
}
}
}
private fun getBooksForGroup(group: BookGroup): List<Book> {
return if (group.groupId == -1L) {
allBooks.take(4)
} else {
allBooks.filter { (it.group and group.groupId) != 0L }.take(4)
}
}
inner class BookViewHolder(val binding: ItemBookshelfListCompactBinding) :
RecyclerView.ViewHolder(binding.root) {
fun onBind(item: Book) = binding.run {
tvName.text = item.name
tvAuthor.text = item.author
tvLast.text = item.latestChapterTitle
ivCover.load(item.getDisplayCover(), item.name, item.author, false, item.origin)
cdUnread.visible()
// ivAuthor.visible()
// ivLast.visible()
// ivRead.visible()
upRefresh(this, item)
upLastUpdateTime(binding, item)
}
fun onBind(item: Book, payloads: MutableList<Any>) = binding.run {
if (payloads.isEmpty()) {
onBind(item)
} else {
for (i in payloads.indices) {
val bundle = payloads[i] as Bundle
bundle.keySet().forEach {
when (it) {
"name" -> tvName.text = item.name
"author" -> tvAuthor.text = item.author
"last" -> tvLast.text = item.latestChapterTitle
"cover" -> ivCover.load(
item.getDisplayCover(),
item.name,
item.author,
false,
item.origin
)
"refresh" -> upRefresh(this, item)
"lastUpdateTime" -> upLastUpdateTime(binding, item)
}
}
}
}
}
private fun upLastUpdateTime(binding: ItemBookshelfListCompactBinding, item: Book) {
if (AppConfig.showLastUpdateTime && !item.isLocal) {
val time = item.latestChapterTime.toTimeAgo()
if (binding.tvLastUpdateTime.text != time) {
binding.tvLastUpdateTime.text = time
}
} else {
binding.tvLastUpdateTime.text = ""
}
}
fun registerListener(item: Any) {
binding.cvContent.setOnClickListener {
callBack.onItemClick(item, binding.cdCover)
}
binding.cvContent.onLongClick {
callBack.onItemLongClick(item, binding.cdCover)
}
}
private fun upRefresh(binding: ItemBookshelfListCompactBinding, item: Book) {
if (!item.isLocal && callBack.isUpdate(item.bookUrl)) {
binding.tvUnread.isVisible = false
binding.rlLoading.isVisible = true
} else {
binding.rlLoading.isVisible = false
if (AppConfig.showUnread) {
//binding.tvUnread.setHighlight(item.lastCheckCount > 0)
binding.tvUnread.isVisible = true
binding.tvUnread.text = item.getUnreadChapterNum().toString()
} else {
binding.tvUnread.isVisible = false
}
}
}
}
inner class GroupViewHolder(val binding: ItemBookshelfListCompactGroupBinding) :
RecyclerView.ViewHolder(binding.root) {
fun onBind(item: BookGroup) = binding.run {
tvName.text = item.groupName
loadGroupCover(item)
cdUnread.gone()
}
fun onBind(item: BookGroup, payloads: MutableList<Any>) = binding.run {
if (payloads.isEmpty()) {
onBind(item)
} else {
for (i in payloads.indices) {
val bundle = payloads[i] as Bundle
bundle.keySet().forEach {
when (it) {
"groupName" -> tvName.text = item.groupName
"cover" -> loadGroupCover(item)
}
}
}
}
}
fun registerListener(item: Any) {
binding.cvContent.setOnClickListener {
callBack.onItemClick(item, binding.ivCover)
}
binding.cvContent.onLongClick {
callBack.onItemLongClick(item, binding.ivCover)
}
}
private fun loadGroupCover(item: BookGroup) = binding.run {
binding.ivCover.setImageDrawable(
ContextCompat.getDrawable(binding.root.context, R.drawable.bg_surface_variant)
)
binding.ivCover1.setImageDrawable(null)
binding.ivCover2.setImageDrawable(null)
if (!item.cover.isNullOrEmpty()) {
ivCover.load(item.cover)
} else {
val books = getBooksForGroup(item)
if (books.size > 0) binding.ivCover1.load(books[0].getDisplayCover())
if (books.size > 1) binding.ivCover2.load(books[1].getDisplayCover())
}
}
}
}