增加[紧凑网格]、[封面网格]书架布局。

This commit is contained in:
HapeLee
2025-09-02 03:22:00 +08:00
parent 701f2826b3
commit 02bc1845a0
13 changed files with 968 additions and 86 deletions
@@ -37,8 +37,8 @@ object PreferKey {
const val enableReview = "enableReview"
const val showRss = "showRss"
const val bookshelfLayout = "bookshelfLayout"
const val bookshelfLayoutPortrait = "bookshelfLayoutPortrait"
const val bookshelfLayoutLandscape = "bookshelf_layout_landscape"
const val bookshelfLayoutModePortrait = "bookshelfLayoutPortrait"
const val bookshelfLayoutModeLandscape = "bookshelf_layout_landscape"
const val bookshelfSort = "bookshelfSort"
const val bookExportFileName = "bookExportFileName"
const val bookImportFileName = "bookImportFileName"
@@ -206,4 +206,10 @@ object PreferKey {
const val notificationsPost = "notificationsPost"
const val ignoreBatteryPermission = "ignoreBatteryPermission"
const val paddingDisplayCutouts = "paddingDisplayCutouts"
const val delayBookLoadEnable = "delayBookLoadEnable"
const val bookshelfLayoutGridLandscape = "bookshelfLayoutGridLandscape"
const val bookshelfLayoutGridPortrait = "bookshelfLayoutGridPortrait"
}
@@ -13,6 +13,7 @@ import io.legato.kazusa.constant.EventBus
import io.legato.kazusa.databinding.DialogBookshelfConfigBinding
import io.legato.kazusa.help.config.AppConfig
import io.legato.kazusa.ui.main.MainViewModel
import io.legato.kazusa.utils.bookshelfLayoutGrid
import io.legato.kazusa.utils.postEvent
import io.legato.kazusa.utils.viewbindingdelegate.viewBinding
@@ -26,13 +27,18 @@ class BookshelfConfigBottomSheet : BaseBottomSheetDialogFragment(R.layout.dialog
val orientation = requireContext().resources.configuration.orientation
val bookshelfLayout = if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
AppConfig.bookshelfLayoutLandscape
AppConfig.bookshelfLayoutModeLandscape
} else {
AppConfig.bookshelfLayoutPortrait
AppConfig.bookshelfLayoutModePortrait
}
val isGrid = bookshelfLayout > 0
val columnCount = bookshelfLayout.takeIf { it > 0 } ?: 1
val isList = bookshelfLayout == 0
val isGrid = bookshelfLayout == 1
val isGridCompact = bookshelfLayout == 2
val isGridCover = bookshelfLayout == 3
val columnCount = requireContext().bookshelfLayoutGrid.takeIf { it > 0 } ?: 1
val bookshelfSort = AppConfig.bookshelfSort
@@ -69,10 +75,12 @@ class BookshelfConfigBottomSheet : BaseBottomSheetDialogFragment(R.layout.dialog
swShowWaitUpBooks.isChecked = AppConfig.showWaitUpCount
swShowBookshelfFastScroller.isChecked = AppConfig.showBookshelfFastScroller
chipList.isChecked = !isGrid
chipList.isChecked = isList
chipGrid.isChecked = isGrid
sliderText.isVisible = isGrid
sliderGridCount.isVisible = isGrid
chipGridCompact.isChecked = isGridCompact
chipGridCover.isChecked = isGridCover
sliderText.isVisible = isGrid || isGridCompact || isGridCover
sliderGridCount.isVisible = isGrid || isGridCompact || isGridCover
sliderGridCount.value = columnCount.toFloat()
when (AppConfig.bookshelfSortOrder) {
@@ -80,10 +88,13 @@ class BookshelfConfigBottomSheet : BaseBottomSheetDialogFragment(R.layout.dialog
1 -> binding.chipGroupOrder.check(binding.chipDesc.id)
}
chipGroupLayout.setOnCheckedStateChangeListener { group, checkedIds ->
sliderText.isVisible = checkedIds.firstOrNull() == R.id.chip_grid
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
TransitionManager.beginDelayedTransition(root)
sliderGridCount.isVisible = checkedIds.firstOrNull() == R.id.chip_grid
sliderGridCount.isVisible = showSlider
}
btnOk.setOnClickListener {
@@ -91,7 +102,9 @@ class BookshelfConfigBottomSheet : BaseBottomSheetDialogFragment(R.layout.dialog
var recreate = false
if (AppConfig.bookGroupStyle != chipGroupStyle.checkedChipId) {
AppConfig.bookGroupStyle = chipGroupStyle.indexOfChild(chipGroupStyle.findViewById(chipGroupStyle.checkedChipId))
AppConfig.bookGroupStyle = chipGroupStyle.indexOfChild(
chipGroupStyle.findViewById(chipGroupStyle.checkedChipId)
)
notifyMain = true
}
@@ -107,7 +120,6 @@ class BookshelfConfigBottomSheet : BaseBottomSheetDialogFragment(R.layout.dialog
AppConfig.showWaitUpCount = swShowWaitUpBooks.isChecked
activityViewModel.postUpBooksLiveData(true)
}
if (AppConfig.showBookshelfFastScroller != swShowBookshelfFastScroller.isChecked) {
AppConfig.showBookshelfFastScroller = swShowBookshelfFastScroller.isChecked
postEvent(EventBus.BOOKSHELF_REFRESH, "")
@@ -118,25 +130,29 @@ class BookshelfConfigBottomSheet : BaseBottomSheetDialogFragment(R.layout.dialog
(requireParentFragment() as? BaseBookshelfFragment)?.upSort()
}
val isNowGrid = chipGrid.isChecked
val selectedColumn = sliderGridCount.value.toInt()
val newLayout = if (isNowGrid) selectedColumn else 0
val newLayout = when {
chipList.isChecked -> 0
chipGrid.isChecked -> 1
chipGridCompact.isChecked -> 2
chipGridCover.isChecked -> 3
else -> 0
}
if (bookshelfLayout != newLayout) {
val oldColumn = requireContext().bookshelfLayoutGrid
if (bookshelfLayout != newLayout || oldColumn != selectedColumn) {
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
AppConfig.bookshelfLayoutLandscape = newLayout
if (newLayout == 0) {
activityViewModel.booksGridRecycledViewPool.clear()
} else {
activityViewModel.booksListRecycledViewPool.clear()
}
AppConfig.bookshelfLayoutModeLandscape = newLayout
AppConfig.bookshelfLayoutGridLandscape = selectedColumn
} else {
AppConfig.bookshelfLayoutPortrait = newLayout
if (newLayout == 0) {
activityViewModel.booksGridRecycledViewPool.clear()
} else {
activityViewModel.booksListRecycledViewPool.clear()
}
AppConfig.bookshelfLayoutModePortrait = newLayout
AppConfig.bookshelfLayoutGridPortrait = selectedColumn
}
if (newLayout == 0) {
activityViewModel.booksGridRecycledViewPool.clear()
} else {
activityViewModel.booksListRecycledViewPool.clear()
}
recreate = true
}
@@ -146,7 +162,6 @@ class BookshelfConfigBottomSheet : BaseBottomSheetDialogFragment(R.layout.dialog
binding.chipDesc.id -> 1
else -> 1
}
if (AppConfig.bookshelfSortOrder != newOrder) {
AppConfig.bookshelfSortOrder = newOrder
(requireParentFragment() as? BaseBookshelfFragment)?.upSort()
@@ -36,8 +36,11 @@ import io.legato.kazusa.ui.book.read.ReadBookActivity
import io.legato.kazusa.ui.main.MainViewModel
import io.legato.kazusa.ui.main.bookshelf.books.styleDefalut.BaseBooksAdapter
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.utils.bookshelfLayout
import io.legato.kazusa.utils.bookshelfLayoutGrid
import io.legato.kazusa.utils.bookshelfLayoutMode
import io.legato.kazusa.utils.cnCompare
import io.legato.kazusa.utils.flowWithLifecycleAndDatabaseChangeFirst
import io.legato.kazusa.utils.observeEvent
@@ -71,14 +74,27 @@ class BooksFragment() : BaseFragment(R.layout.fragment_books),
private val binding by viewBinding(FragmentBooksBinding::bind)
private val activityViewModel by activityViewModels<MainViewModel>()
private val bookshelfLayout by lazy { requireContext().bookshelfLayout }
private val bookshelfLayoutMode by lazy { requireContext().bookshelfLayoutMode }
private val bookshelfLayoutGrid by lazy { requireContext().bookshelfLayoutGrid }
private val booksAdapter: BaseBooksAdapter<*> by lazy {
if (bookshelfLayout == 0) {
BooksAdapterList(requireContext(), this, this, viewLifecycleOwner.lifecycle)
} else {
BooksAdapterGrid(requireContext(), this)
when (bookshelfLayoutMode) {
0 -> {
BooksAdapterList(requireContext(), this, this, viewLifecycleOwner.lifecycle)
}
1 -> {
BooksAdapterGrid(requireContext(), this)
}
2 -> {
BooksAdapterGridCompact(requireContext(), this)
}
else -> {
BooksAdapterGridCover(requireContext(), this)
}
}
}
private var booksFlowJob: Job? = null
@@ -111,14 +127,11 @@ class BooksFragment() : BaseFragment(R.layout.fragment_books),
binding.refreshLayout.isRefreshing = false
activityViewModel.upToc(booksAdapter.getItems())
}
if (bookshelfLayout == 0) {
if (bookshelfLayoutMode == 0) {
binding.rvBookshelf.layoutManager = LinearLayoutManager(context)
} else {
binding.rvBookshelf.layoutManager = GridLayoutManager(context, bookshelfLayout)
}
if (bookshelfLayout == 0) {
binding.rvBookshelf.setRecycledViewPool(activityViewModel.booksListRecycledViewPool)
} else {
binding.rvBookshelf.layoutManager = GridLayoutManager(context, bookshelfLayoutGrid)
binding.rvBookshelf.setRecycledViewPool(activityViewModel.booksGridRecycledViewPool)
}
booksAdapter.stateRestorationPolicy = StateRestorationPolicy.PREVENT_WHEN_EMPTY
@@ -219,7 +232,7 @@ class BooksFragment() : BaseFragment(R.layout.fragment_books),
private fun startLastUpdateTimeJob() {
upLastUpdateTimeJob?.cancel()
if (!AppConfig.showLastUpdateTime || bookshelfLayout != 0) {
if (!AppConfig.showLastUpdateTime || bookshelfLayoutMode != 0) {
return
}
upLastUpdateTimeJob = lifecycleScope.launch {
@@ -33,8 +33,11 @@ import io.legato.kazusa.ui.book.search.SearchActivity
import io.legato.kazusa.ui.main.bookshelf.BaseBookshelfFragment
import io.legato.kazusa.ui.main.bookshelf.books.styleFold.BaseBooksAdapter
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.utils.bookshelfLayout
import io.legato.kazusa.utils.bookshelfLayoutGrid
import io.legato.kazusa.utils.bookshelfLayoutMode
import io.legato.kazusa.utils.cnCompare
import io.legato.kazusa.utils.flowWithLifecycleAndDatabaseChangeFirst
import io.legato.kazusa.utils.observeEvent
@@ -64,13 +67,27 @@ class BookshelfFragment2() : BaseBookshelfFragment(R.layout.fragment_bookshelf2)
private val binding by viewBinding(FragmentBookshelf2Binding::bind)
private val bookshelfLayout by lazy { requireContext().bookshelfLayout }
private val bookshelfLayoutMode by lazy { requireContext().bookshelfLayoutMode }
private val bookshelfLayoutGrid by lazy { requireContext().bookshelfLayoutGrid }
private val booksAdapter: BaseBooksAdapter<*> by lazy {
if (bookshelfLayout == 0) {
BooksAdapterList(requireContext(), this)
} else {
BooksAdapterGrid(requireContext(), this)
when (bookshelfLayoutMode) {
0 -> {
BooksAdapterList(requireContext(), this)
}
1 -> {
BooksAdapterGrid(requireContext(), this)
}
2 -> {
BooksAdapterGridCompact(requireContext(), this)
}
else -> {
BooksAdapterGridCover(requireContext(), this)
}
}
}
@@ -94,10 +111,10 @@ class BookshelfFragment2() : BaseBookshelfFragment(R.layout.fragment_bookshelf2)
binding.refreshLayout.isRefreshing = false
activityViewModel.upToc(books)
}
if (bookshelfLayout == 0) {
if (bookshelfLayoutMode == 0) {
binding.rvBookshelf.layoutManager = LinearLayoutManager(context)
} else {
binding.rvBookshelf.layoutManager = GridLayoutManager(context, bookshelfLayout)
binding.rvBookshelf.layoutManager = GridLayoutManager(context, bookshelfLayoutGrid)
}
binding.rvBookshelf.itemAnimator = null
binding.rvBookshelf.adapter = booksAdapter
@@ -0,0 +1,90 @@
package io.legato.kazusa.ui.main.bookshelf.books.styleDefalut
import android.content.Context
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import io.legato.kazusa.base.adapter.ItemViewHolder
import io.legato.kazusa.data.entities.Book
import io.legato.kazusa.databinding.ItemBookshelfGridCompactBinding
import io.legato.kazusa.help.book.isLocal
import io.legato.kazusa.help.config.AppConfig
class BooksAdapterGridCompact(context: Context, private val callBack: CallBack) :
BaseBooksAdapter<ItemBookshelfGridCompactBinding>(context) {
override fun getViewBinding(parent: ViewGroup): ItemBookshelfGridCompactBinding {
return ItemBookshelfGridCompactBinding.inflate(inflater, parent, false)
}
override fun convert(
holder: ItemViewHolder,
binding: ItemBookshelfGridCompactBinding,
item: Book,
payloads: MutableList<Any>
) = binding.run {
binding.ivCover.transitionName = "book_${item.bookUrl}"
if (payloads.isEmpty()) {
tvName.text = item.name
ivCover.load(item.getDisplayCover(), item.name, item.author, false, item.origin)
upRefresh(binding, item)
} else {
for (i in payloads.indices) {
val bundle = payloads[i] as Bundle
bundle.keySet().forEach {
when (it) {
"name" -> tvName.text = item.name
"cover" -> ivCover.load(
item.getDisplayCover(),
item.name,
item.author,
false,
item.origin
)
"refresh" -> upRefresh(binding, item)
}
}
}
}
}
private fun upRefresh(binding: ItemBookshelfGridCompactBinding, item: Book) {
if (!item.isLocal && callBack.isUpdate(item.bookUrl)) {
binding.cdUnread.visibility = View.GONE
binding.rlLoading.visibility = View.VISIBLE
} else {
binding.rlLoading.visibility = View.GONE
if (AppConfig.showUnread) {
val unreadCount = item.getUnreadChapterNum()
if (unreadCount > 0) {
binding.cdUnread.visibility = View.VISIBLE
binding.tvUnread.text = unreadCount.toString()
} else {
binding.cdUnread.visibility = View.GONE
}
} else {
binding.cdUnread.visibility = View.GONE
}
}
}
override fun registerListener(
holder: ItemViewHolder,
binding: ItemBookshelfGridCompactBinding
) {
binding.cvContent.setOnClickListener {
getItem(holder.layoutPosition)?.let {
callBack.open(it, binding.ivCover)
}
}
binding.cvContent.setOnLongClickListener {
getItem(holder.layoutPosition)?.let {
callBack.openBookInfo(it, binding.ivCover)
}
true
}
}
}
@@ -0,0 +1,91 @@
package io.legato.kazusa.ui.main.bookshelf.books.styleDefalut
import android.content.Context
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import io.legato.kazusa.base.adapter.ItemViewHolder
import io.legato.kazusa.data.entities.Book
import io.legato.kazusa.databinding.ItemBookshelfGridCompactBinding
import io.legato.kazusa.help.book.isLocal
import io.legato.kazusa.help.config.AppConfig
import io.legato.kazusa.utils.gone
class BooksAdapterGridCover(context: Context, private val callBack: CallBack) :
BaseBooksAdapter<ItemBookshelfGridCompactBinding>(context) {
override fun getViewBinding(parent: ViewGroup): ItemBookshelfGridCompactBinding {
return ItemBookshelfGridCompactBinding.inflate(inflater, parent, false)
}
override fun convert(
holder: ItemViewHolder,
binding: ItemBookshelfGridCompactBinding,
item: Book,
payloads: MutableList<Any>
) = binding.run {
binding.ivCover.transitionName = "book_${item.bookUrl}"
if (payloads.isEmpty()) {
tvName.gone()
ivCover.load(item.getDisplayCover(), item.name, item.author, false, item.origin)
upRefresh(binding, item)
} else {
for (i in payloads.indices) {
val bundle = payloads[i] as Bundle
bundle.keySet().forEach {
when (it) {
"name" -> tvName.gone()
"cover" -> ivCover.load(
item.getDisplayCover(),
item.name,
item.author,
false,
item.origin
)
"refresh" -> upRefresh(binding, item)
}
}
}
}
}
private fun upRefresh(binding: ItemBookshelfGridCompactBinding, item: Book) {
if (!item.isLocal && callBack.isUpdate(item.bookUrl)) {
binding.cdUnread.visibility = View.GONE
binding.rlLoading.visibility = View.VISIBLE
} else {
binding.rlLoading.visibility = View.GONE
if (AppConfig.showUnread) {
val unreadCount = item.getUnreadChapterNum()
if (unreadCount > 0) {
binding.cdUnread.visibility = View.VISIBLE
binding.tvUnread.text = unreadCount.toString()
} else {
binding.cdUnread.visibility = View.GONE
}
} else {
binding.cdUnread.visibility = View.GONE
}
}
}
override fun registerListener(
holder: ItemViewHolder,
binding: ItemBookshelfGridCompactBinding
) {
binding.cvContent.setOnClickListener {
getItem(holder.layoutPosition)?.let {
callBack.open(it, binding.ivCover)
}
}
binding.cvContent.setOnLongClickListener {
getItem(holder.layoutPosition)?.let {
callBack.openBookInfo(it, binding.ivCover)
}
true
}
}
}
@@ -0,0 +1,190 @@
package io.legato.kazusa.ui.main.bookshelf.books.styleFold
import android.content.Context
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
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.ItemBookshelfGridCompactBinding
import io.legato.kazusa.databinding.ItemBookshelfGridCompactGroupBinding
import io.legato.kazusa.help.book.isLocal
import io.legato.kazusa.help.config.AppConfig
import io.legato.kazusa.utils.gone
import splitties.views.onLongClick
@Suppress("UNUSED_PARAMETER")
class BooksAdapterGridCompact(context: Context, callBack: CallBack) :
BaseBooksAdapter<RecyclerView.ViewHolder>(context, callBack) {
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): RecyclerView.ViewHolder {
return when (viewType) {
1 -> GroupViewHolder(
ItemBookshelfGridCompactGroupBinding.inflate(
inflater,
parent,
false
)
)
else -> BookViewHolder(ItemBookshelfGridCompactBinding.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: ItemBookshelfGridCompactBinding) :
RecyclerView.ViewHolder(binding.root) {
fun onBind(item: Book) = binding.run {
tvName.text = item.name
ivCover.load(item.getDisplayCover(), item.name, item.author, false, item.origin)
upRefresh(this, 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
"cover" -> ivCover.load(
item.getDisplayCover(),
item.name,
item.author,
false,
item.origin
)
"refresh" -> upRefresh(this, item)
}
}
}
}
}
fun registerListener(item: Any) {
binding.cvContent.setOnClickListener {
callBack.onItemClick(item, binding.ivCover)
}
binding.cvContent.onLongClick {
callBack.onItemLongClick(item, binding.ivCover)
}
}
private fun upRefresh(binding: ItemBookshelfGridCompactBinding, item: Book) {
if (!item.isLocal && callBack.isUpdate(item.bookUrl)) {
binding.cdUnread.visibility = View.GONE
binding.rlLoading.visibility = View.VISIBLE
} else {
binding.rlLoading.visibility = View.GONE
if (AppConfig.showUnread) {
val unreadCount = item.getUnreadChapterNum()
if (unreadCount > 0) {
binding.cdUnread.visibility = View.VISIBLE
binding.tvUnread.text = unreadCount.toString()
} else {
binding.cdUnread.visibility = View.GONE
}
} else {
binding.cdUnread.visibility = View.GONE
}
}
}
}
inner class GroupViewHolder(val binding: ItemBookshelfGridCompactGroupBinding) :
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)
binding.ivCover3.setImageDrawable(null)
binding.ivCover4.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())
if (books.size > 2) binding.ivCover3.load(books[2].getDisplayCover())
if (books.size > 3) binding.ivCover4.load(books[3].getDisplayCover())
}
}
}
}
@@ -0,0 +1,190 @@
package io.legato.kazusa.ui.main.bookshelf.books.styleFold
import android.content.Context
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
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.ItemBookshelfGridCompactBinding
import io.legato.kazusa.databinding.ItemBookshelfGridCompactGroupBinding
import io.legato.kazusa.help.book.isLocal
import io.legato.kazusa.help.config.AppConfig
import io.legato.kazusa.utils.gone
import splitties.views.onLongClick
@Suppress("UNUSED_PARAMETER")
class BooksAdapterGridCover(context: Context, callBack: CallBack) :
BaseBooksAdapter<RecyclerView.ViewHolder>(context, callBack) {
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): RecyclerView.ViewHolder {
return when (viewType) {
1 -> GroupViewHolder(
ItemBookshelfGridCompactGroupBinding.inflate(
inflater,
parent,
false
)
)
else -> BookViewHolder(ItemBookshelfGridCompactBinding.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: ItemBookshelfGridCompactBinding) :
RecyclerView.ViewHolder(binding.root) {
fun onBind(item: Book) = binding.run {
tvName.gone()
ivCover.load(item.getDisplayCover(), item.name, item.author, false, item.origin)
upRefresh(this, 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.gone()
"cover" -> ivCover.load(
item.getDisplayCover(),
item.name,
item.author,
false,
item.origin
)
"refresh" -> upRefresh(this, item)
}
}
}
}
}
fun registerListener(item: Any) {
binding.cvContent.setOnClickListener {
callBack.onItemClick(item, binding.ivCover)
}
binding.cvContent.onLongClick {
callBack.onItemLongClick(item, binding.ivCover)
}
}
private fun upRefresh(binding: ItemBookshelfGridCompactBinding, item: Book) {
if (!item.isLocal && callBack.isUpdate(item.bookUrl)) {
binding.cdUnread.visibility = View.GONE
binding.rlLoading.visibility = View.VISIBLE
} else {
binding.rlLoading.visibility = View.GONE
if (AppConfig.showUnread) {
val unreadCount = item.getUnreadChapterNum()
if (unreadCount > 0) {
binding.cdUnread.visibility = View.VISIBLE
binding.tvUnread.text = unreadCount.toString()
} else {
binding.cdUnread.visibility = View.GONE
}
} else {
binding.cdUnread.visibility = View.GONE
}
}
}
}
inner class GroupViewHolder(val binding: ItemBookshelfGridCompactGroupBinding) :
RecyclerView.ViewHolder(binding.root) {
fun onBind(item: BookGroup) = binding.run {
tvName.gone()
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.gone()
"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)
binding.ivCover3.setImageDrawable(null)
binding.ivCover4.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())
if (books.size > 2) binding.ivCover3.load(books[2].getDisplayCover())
if (books.size > 3) binding.ivCover4.load(books[3].getDisplayCover())
}
}
}
}
@@ -420,11 +420,18 @@ val Context.isDebuggable: Boolean
val Context.dataStore by preferencesDataStore(name = "settings")
val Context.bookshelfLayout: Int
val Context.bookshelfLayoutMode: Int
get() = if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
AppConfig.bookshelfLayoutLandscape
AppConfig.bookshelfLayoutModeLandscape
} else {
AppConfig.bookshelfLayoutPortrait
AppConfig.bookshelfLayoutModePortrait
}
val Context.bookshelfLayoutGrid: Int
get() = if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
AppConfig.bookshelfLayoutGridLandscape
} else {
AppConfig.bookshelfLayoutGridPortrait
}
fun Context.themeColor(attr: Int): Int {