Merge branch 'feature/grid-chapters' of github.com:jsericksk/Kotatsu into jsericksk-feature/grid-chapters
This commit is contained in:
@@ -182,6 +182,10 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) {
|
||||
get() = prefs.getBoolean(KEY_REVERSE_CHAPTERS, false)
|
||||
set(value) = prefs.edit { putBoolean(KEY_REVERSE_CHAPTERS, value) }
|
||||
|
||||
var chaptersGridView: Boolean
|
||||
get() = prefs.getBoolean(KEY_GRID_VIEW_CHAPTERS, false)
|
||||
set(value) = prefs.edit { putBoolean(KEY_GRID_VIEW_CHAPTERS, value) }
|
||||
|
||||
val zoomMode: ZoomMode
|
||||
get() = prefs.getEnumValue(KEY_ZOOM_MODE, ZoomMode.FIT_CENTER)
|
||||
|
||||
@@ -552,6 +556,7 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) {
|
||||
const val KEY_HISTORY_GROUPING = "history_grouping"
|
||||
const val KEY_READING_INDICATORS = "reading_indicators"
|
||||
const val KEY_REVERSE_CHAPTERS = "reverse_chapters"
|
||||
const val KEY_GRID_VIEW_CHAPTERS = "grid_view_chapters"
|
||||
const val KEY_HISTORY_EXCLUDE_NSFW = "history_exclude_nsfw"
|
||||
const val KEY_PAGES_NUMBERS = "pages_numbers"
|
||||
const val KEY_SCREENSHOTS_POLICY = "screenshots_policy"
|
||||
|
||||
@@ -28,8 +28,9 @@ class ChaptersMenuProvider(
|
||||
}
|
||||
|
||||
override fun onPrepareMenu(menu: Menu) {
|
||||
menu.findItem(R.id.action_reversed)?.isChecked = viewModel.isChaptersReversed.value == true
|
||||
menu.findItem(R.id.action_search)?.isVisible = viewModel.isChaptersEmpty.value == false
|
||||
menu.findItem(R.id.action_reversed)?.isChecked = viewModel.isChaptersReversed.value == true
|
||||
menu.findItem(R.id.action_grid_view)?.isChecked = viewModel.isChaptersInGridView.value == true
|
||||
}
|
||||
|
||||
override fun onMenuItemSelected(menuItem: MenuItem): Boolean = when (menuItem.itemId) {
|
||||
@@ -37,6 +38,10 @@ class ChaptersMenuProvider(
|
||||
viewModel.setChaptersReversed(!menuItem.isChecked)
|
||||
true
|
||||
}
|
||||
R.id.action_grid_view-> {
|
||||
viewModel.setChaptersInGridView(!menuItem.isChecked)
|
||||
true
|
||||
}
|
||||
|
||||
else -> false
|
||||
}
|
||||
|
||||
@@ -125,6 +125,12 @@ class DetailsViewModel @Inject constructor(
|
||||
valueProducer = { chaptersReverse },
|
||||
)
|
||||
|
||||
val isChaptersInGridView = settings.observeAsStateFlow(
|
||||
scope = viewModelScope + Dispatchers.Default,
|
||||
key = AppSettings.KEY_GRID_VIEW_CHAPTERS,
|
||||
valueProducer = { chaptersGridView },
|
||||
)
|
||||
|
||||
val historyInfo: StateFlow<HistoryInfo> = combine(
|
||||
manga,
|
||||
selectedBranch,
|
||||
@@ -285,6 +291,10 @@ class DetailsViewModel @Inject constructor(
|
||||
settings.chaptersReverse = newValue
|
||||
}
|
||||
|
||||
fun setChaptersInGridView(newValue: Boolean) {
|
||||
settings.chaptersGridView = newValue
|
||||
}
|
||||
|
||||
fun setSelectedBranch(branch: String?) {
|
||||
selectedBranch.value = branch
|
||||
}
|
||||
|
||||
@@ -10,14 +10,24 @@ import org.koitharu.kotatsu.list.ui.adapter.listHeaderAD
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
|
||||
class ChaptersAdapter(
|
||||
onItemClickListener: OnListItemClickListener<ChapterListItem>,
|
||||
private val onItemClickListener: OnListItemClickListener<ChapterListItem>,
|
||||
chaptersInGridView: Boolean,
|
||||
) : BaseListAdapter<ListModel>(), FastScroller.SectionIndexer {
|
||||
|
||||
init {
|
||||
addDelegate(ListItemType.CHAPTER, chapterListItemAD(onItemClickListener))
|
||||
setChapterAdapterDelegate(chaptersInGridView)
|
||||
addDelegate(ListItemType.HEADER, listHeaderAD(null))
|
||||
}
|
||||
|
||||
fun setChapterAdapterDelegate(chaptersInGridView: Boolean) {
|
||||
delegatesManager.removeDelegate(ListItemType.CHAPTER.ordinal)
|
||||
if (chaptersInGridView) {
|
||||
addDelegate(ListItemType.CHAPTER, chapterGridItemAD(onItemClickListener))
|
||||
} else {
|
||||
addDelegate(ListItemType.CHAPTER, chapterListItemAD(onItemClickListener))
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSectionText(context: Context, position: Int): CharSequence? {
|
||||
return findHeader(position)?.getText(context)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package org.koitharu.kotatsu.details.ui.adapter
|
||||
|
||||
import android.graphics.Typeface
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isVisible
|
||||
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.ui.list.AdapterDelegateClickListenerAdapter
|
||||
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.core.util.ext.drawableStart
|
||||
import org.koitharu.kotatsu.core.util.ext.getThemeColorStateList
|
||||
import org.koitharu.kotatsu.databinding.ItemChapterGridBinding
|
||||
import org.koitharu.kotatsu.details.ui.model.ChapterListItem
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
fun chapterGridItemAD(
|
||||
clickListener: OnListItemClickListener<ChapterListItem>,
|
||||
) = adapterDelegateViewBinding<ChapterListItem, ListModel, ItemChapterGridBinding>(
|
||||
{ inflater, parent -> ItemChapterGridBinding.inflate(inflater, parent, false) },
|
||||
) {
|
||||
|
||||
val eventListener = AdapterDelegateClickListenerAdapter(this, clickListener)
|
||||
itemView.setOnClickListener(eventListener)
|
||||
itemView.setOnLongClickListener(eventListener)
|
||||
|
||||
bind { payloads ->
|
||||
if (payloads.isEmpty()) {
|
||||
binding.textViewTitle.text = item.chapter.number.roundToInt().toString()
|
||||
}
|
||||
when {
|
||||
item.isCurrent -> {
|
||||
binding.textViewTitle.drawableStart = ContextCompat.getDrawable(context, R.drawable.ic_current_chapter)
|
||||
binding.textViewTitle.setTextColor(context.getThemeColorStateList(android.R.attr.textColorPrimary))
|
||||
binding.textViewTitle.typeface = Typeface.DEFAULT_BOLD
|
||||
}
|
||||
|
||||
item.isUnread -> {
|
||||
binding.textViewTitle.drawableStart = if (item.isNew) {
|
||||
ContextCompat.getDrawable(context, R.drawable.ic_new)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
binding.textViewTitle.setTextColor(context.getThemeColorStateList(android.R.attr.textColorPrimary))
|
||||
binding.textViewTitle.typeface = Typeface.DEFAULT
|
||||
}
|
||||
|
||||
else -> {
|
||||
binding.textViewTitle.drawableStart = null
|
||||
binding.textViewTitle.setTextColor(context.getThemeColorStateList(android.R.attr.textColorHint))
|
||||
binding.textViewTitle.typeface = Typeface.DEFAULT
|
||||
}
|
||||
}
|
||||
binding.imageViewBookmarked.isVisible = item.isBookmarked
|
||||
binding.imageViewDownloaded.isVisible = item.isDownloaded
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.koitharu.kotatsu.details.ui.pager.chapters
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
@@ -11,6 +12,8 @@ import androidx.core.graphics.Insets
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
@@ -55,7 +58,7 @@ class ChaptersFragment :
|
||||
|
||||
override fun onViewBindingCreated(binding: FragmentChaptersBinding, savedInstanceState: Bundle?) {
|
||||
super.onViewBindingCreated(binding, savedInstanceState)
|
||||
chaptersAdapter = ChaptersAdapter(this)
|
||||
chaptersAdapter = ChaptersAdapter(this, viewModel.isChaptersInGridView.value)
|
||||
selectionController = ListSelectionController(
|
||||
activity = requireActivity(),
|
||||
decoration = ChaptersSelectionDecoration(binding.root.context),
|
||||
@@ -67,7 +70,15 @@ class ChaptersFragment :
|
||||
checkNotNull(selectionController).attachToRecyclerView(this)
|
||||
setHasFixedSize(true)
|
||||
isNestedScrollingEnabled = false
|
||||
adapter = chaptersAdapter
|
||||
}
|
||||
viewModel.isChaptersInGridView.observe(viewLifecycleOwner) { chaptersInGridView ->
|
||||
chaptersAdapter?.setChapterAdapterDelegate(chaptersInGridView)
|
||||
binding.recyclerViewChapters.adapter = chaptersAdapter
|
||||
binding.recyclerViewChapters.layoutManager = if (chaptersInGridView) {
|
||||
GridLayoutManager(context, 4)
|
||||
} else {
|
||||
LinearLayoutManager(context)
|
||||
}
|
||||
}
|
||||
viewModel.isLoading.observe(viewLifecycleOwner, this::onLoadingStateChanged)
|
||||
viewModel.chapters
|
||||
|
||||
@@ -6,6 +6,8 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.MangaHistory
|
||||
@@ -75,7 +77,8 @@ class ChaptersSheet : BaseAdaptiveSheet<SheetChaptersBinding>(),
|
||||
-1
|
||||
}
|
||||
binding.recyclerView.addItemDecoration(TypedListSpacingDecoration(binding.recyclerView.context, true))
|
||||
binding.recyclerView.adapter = ChaptersAdapter(this).also { adapter ->
|
||||
val chaptersInGridView = settings.chaptersGridView
|
||||
binding.recyclerView.adapter = ChaptersAdapter(this, chaptersInGridView).also { adapter ->
|
||||
if (currentPosition >= 0) {
|
||||
val targetPosition = (currentPosition - 1).coerceAtLeast(0)
|
||||
val offset =
|
||||
@@ -87,6 +90,11 @@ class ChaptersSheet : BaseAdaptiveSheet<SheetChaptersBinding>(),
|
||||
adapter.items = chapters
|
||||
}
|
||||
}
|
||||
binding.recyclerView.layoutManager = if (chaptersInGridView) {
|
||||
GridLayoutManager(context, 4)
|
||||
} else {
|
||||
LinearLayoutManager(context)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onItemClick(item: ChapterListItem, view: View) {
|
||||
|
||||
68
app/src/main/res/layout/item_chapter_grid.xml
Normal file
68
app/src/main/res/layout/item_chapter_grid.xml
Normal file
@@ -0,0 +1,68 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_margin="6dp"
|
||||
android:clipChildren="false"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintDimensionRatio="H,1:1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?attr/textAppearanceBodyLarge"
|
||||
tools:text="150"
|
||||
tools:textColor="?android:textColorPrimary" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="6dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView_bookmarked"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:contentDescription="@string/bookmarks"
|
||||
app:srcCompat="@drawable/ic_bookmark" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView_downloaded"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:contentDescription="@string/downloaded"
|
||||
app:srcCompat="@drawable/ic_save_ok" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -18,4 +18,11 @@
|
||||
android:title="@string/reverse"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_grid_view"
|
||||
android:checkable="true"
|
||||
android:orderInCategory="30"
|
||||
android:title="@string/chapters_grid_view"
|
||||
app:showAsAction="never" />
|
||||
|
||||
</menu>
|
||||
|
||||
@@ -173,6 +173,7 @@
|
||||
<string name="text_clear_updates_feed_prompt">Clear all update history permanently?</string>
|
||||
<string name="check_for_new_chapters">Check for new chapters</string>
|
||||
<string name="reverse">Reverse</string>
|
||||
<string name="chapters_grid_view">Grid view</string>
|
||||
<string name="sign_in">Sign in</string>
|
||||
<string name="auth_required">Sign in to view this content</string>
|
||||
<string name="default_s">Default: %s</string>
|
||||
|
||||
Reference in New Issue
Block a user