diff --git a/app/src/main/java/io/legato/kazusa/ui/main/bookshelf/BookshelfConfigBottomSheet.kt b/app/src/main/java/io/legato/kazusa/ui/main/bookshelf/BookshelfConfigBottomSheet.kt index a6293e4db..ef93cf823 100644 --- a/app/src/main/java/io/legato/kazusa/ui/main/bookshelf/BookshelfConfigBottomSheet.kt +++ b/app/src/main/java/io/legato/kazusa/ui/main/bookshelf/BookshelfConfigBottomSheet.kt @@ -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() diff --git a/app/src/main/java/io/legato/kazusa/ui/main/bookshelf/books/BooksFragment.kt b/app/src/main/java/io/legato/kazusa/ui/main/bookshelf/books/BooksFragment.kt index 09f3dc848..e61b81c9a 100644 --- a/app/src/main/java/io/legato/kazusa/ui/main/bookshelf/books/BooksFragment.kt +++ b/app/src/main/java/io/legato/kazusa/ui/main/bookshelf/books/BooksFragment.kt @@ -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 { diff --git a/app/src/main/java/io/legato/kazusa/ui/main/bookshelf/books/BookshelfFragment2.kt b/app/src/main/java/io/legato/kazusa/ui/main/bookshelf/books/BookshelfFragment2.kt index 77f8f5854..6670b2846 100644 --- a/app/src/main/java/io/legato/kazusa/ui/main/bookshelf/books/BookshelfFragment2.kt +++ b/app/src/main/java/io/legato/kazusa/ui/main/bookshelf/books/BookshelfFragment2.kt @@ -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) diff --git a/app/src/main/java/io/legato/kazusa/ui/main/bookshelf/books/styleDefalut/BooksAdapterListCompact.kt b/app/src/main/java/io/legato/kazusa/ui/main/bookshelf/books/styleDefalut/BooksAdapterListCompact.kt new file mode 100644 index 000000000..741673e04 --- /dev/null +++ b/app/src/main/java/io/legato/kazusa/ui/main/bookshelf/books/styleDefalut/BooksAdapterListCompact.kt @@ -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(context) { + + override fun getViewBinding(parent: ViewGroup): ItemBookshelfListCompactBinding { + return ItemBookshelfListCompactBinding.inflate(inflater, parent, false) + } + + override fun convert( + holder: ItemViewHolder, + binding: ItemBookshelfListCompactBinding, + item: Book, + payloads: MutableList + ) = 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) + } + } + } + } +} diff --git a/app/src/main/java/io/legato/kazusa/ui/main/bookshelf/books/styleFold/BooksAdapterList.kt b/app/src/main/java/io/legato/kazusa/ui/main/bookshelf/books/styleFold/BooksAdapterList.kt index 2c2dd0570..ac081587f 100644 --- a/app/src/main/java/io/legato/kazusa/ui/main/bookshelf/books/styleFold/BooksAdapterList.kt +++ b/app/src/main/java/io/legato/kazusa/ui/main/bookshelf/books/styleFold/BooksAdapterList.kt @@ -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) } diff --git a/app/src/main/java/io/legato/kazusa/ui/main/bookshelf/books/styleFold/BooksAdapterListCompact.kt b/app/src/main/java/io/legato/kazusa/ui/main/bookshelf/books/styleFold/BooksAdapterListCompact.kt new file mode 100644 index 000000000..6ef992ebc --- /dev/null +++ b/app/src/main/java/io/legato/kazusa/ui/main/bookshelf/books/styleFold/BooksAdapterListCompact.kt @@ -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(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 + ) { + 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 { + 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) = 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) = 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()) + } + } + + } + +} \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_bookshelf_config.xml b/app/src/main/res/layout/dialog_bookshelf_config.xml index 69a111992..81ef7c153 100644 --- a/app/src/main/res/layout/dialog_bookshelf_config.xml +++ b/app/src/main/res/layout/dialog_bookshelf_config.xml @@ -111,6 +111,13 @@ android:checkable="true" android:text="@string/list" /> + + - - - + android:gravity="center_vertical" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toEndOf="@id/cd_cover" + app:layout_constraintEnd_toEndOf="parent"> - + - + - + - + - + - + - + + diff --git a/app/src/main/res/layout/item_bookshelf_list_compact.xml b/app/src/main/res/layout/item_bookshelf_list_compact.xml new file mode 100644 index 000000000..9b81e0129 --- /dev/null +++ b/app/src/main/res/layout/item_bookshelf_list_compact.xml @@ -0,0 +1,169 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_bookshelf_list_compact_group.xml b/app/src/main/res/layout/item_bookshelf_list_compact_group.xml new file mode 100644 index 000000000..c50d21af7 --- /dev/null +++ b/app/src/main/res/layout/item_bookshelf_list_compact_group.xml @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_bookshelf_list_group.xml b/app/src/main/res/layout/item_bookshelf_list_group.xml index da6c4b32a..a55bf06e7 100644 --- a/app/src/main/res/layout/item_bookshelf_list_group.xml +++ b/app/src/main/res/layout/item_bookshelf_list_group.xml @@ -4,7 +4,6 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginVertical="4dp" app:strokeWidth="0dp"> diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index 5516363d8..7907f0b74 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -1284,4 +1284,6 @@ 使用共享元素动画 减少进入阅读界面时的卡顿,但加载书籍时间会延长。 延缓书籍加载 + 紧凑列表 + %s • %d章未读 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9405d0f84..df9c68fc8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1285,4 +1285,6 @@ Use Shared Element Animation Reduces stutter when entering the reading interface, but increases book loading time. Delay Book Loading + Compact List + %s • %dNot read