|
|
|
|
@ -2,8 +2,13 @@ package org.koitharu.kotatsu.details.ui.pager.pages
|
|
|
|
|
|
|
|
|
|
import android.os.Bundle
|
|
|
|
|
import android.view.LayoutInflater
|
|
|
|
|
import android.view.Menu
|
|
|
|
|
import android.view.MenuInflater
|
|
|
|
|
import android.view.MenuItem
|
|
|
|
|
import android.view.View
|
|
|
|
|
import android.view.ViewGroup
|
|
|
|
|
import androidx.appcompat.view.ActionMode
|
|
|
|
|
import androidx.collection.ArraySet
|
|
|
|
|
import androidx.core.graphics.Insets
|
|
|
|
|
import androidx.core.view.isInvisible
|
|
|
|
|
import androidx.core.view.isVisible
|
|
|
|
|
@ -20,10 +25,12 @@ import org.koitharu.kotatsu.core.exceptions.resolve.SnackbarErrorObserver
|
|
|
|
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
|
|
|
|
import org.koitharu.kotatsu.core.ui.BaseFragment
|
|
|
|
|
import org.koitharu.kotatsu.core.ui.list.BoundsScrollListener
|
|
|
|
|
import org.koitharu.kotatsu.core.ui.list.ListSelectionController
|
|
|
|
|
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
|
|
|
|
|
import org.koitharu.kotatsu.core.ui.util.PagerNestedScrollHelper
|
|
|
|
|
import org.koitharu.kotatsu.core.util.RecyclerViewScrollCallback
|
|
|
|
|
import org.koitharu.kotatsu.core.util.ext.dismissParentDialog
|
|
|
|
|
import org.koitharu.kotatsu.core.util.ext.findAppCompatDelegate
|
|
|
|
|
import org.koitharu.kotatsu.core.util.ext.findParentCallback
|
|
|
|
|
import org.koitharu.kotatsu.core.util.ext.observe
|
|
|
|
|
import org.koitharu.kotatsu.core.util.ext.observeEvent
|
|
|
|
|
@ -34,16 +41,18 @@ import org.koitharu.kotatsu.list.ui.GridSpanResolver
|
|
|
|
|
import org.koitharu.kotatsu.list.ui.adapter.ListItemType
|
|
|
|
|
import org.koitharu.kotatsu.list.ui.adapter.TypedListSpacingDecoration
|
|
|
|
|
import org.koitharu.kotatsu.list.ui.model.ListModel
|
|
|
|
|
import org.koitharu.kotatsu.reader.ui.PageSaveHelper
|
|
|
|
|
import org.koitharu.kotatsu.reader.ui.ReaderActivity.IntentBuilder
|
|
|
|
|
import org.koitharu.kotatsu.reader.ui.ReaderNavigationCallback
|
|
|
|
|
import org.koitharu.kotatsu.reader.ui.ReaderState
|
|
|
|
|
import org.koitharu.kotatsu.reader.ui.pager.ReaderPage
|
|
|
|
|
import javax.inject.Inject
|
|
|
|
|
import kotlin.math.roundToInt
|
|
|
|
|
|
|
|
|
|
@AndroidEntryPoint
|
|
|
|
|
class PagesFragment :
|
|
|
|
|
BaseFragment<FragmentPagesBinding>(),
|
|
|
|
|
OnListItemClickListener<PageThumbnail> {
|
|
|
|
|
OnListItemClickListener<PageThumbnail>, ListSelectionController.Callback {
|
|
|
|
|
|
|
|
|
|
@Inject
|
|
|
|
|
lateinit var coil: ImageLoader
|
|
|
|
|
@ -51,17 +60,23 @@ class PagesFragment :
|
|
|
|
|
@Inject
|
|
|
|
|
lateinit var settings: AppSettings
|
|
|
|
|
|
|
|
|
|
@Inject
|
|
|
|
|
lateinit var pageSaveHelperFactory: PageSaveHelper.Factory
|
|
|
|
|
|
|
|
|
|
private val parentViewModel by ChaptersPagesViewModel.ActivityVMLazy(this)
|
|
|
|
|
private val viewModel by viewModels<PagesViewModel>()
|
|
|
|
|
private lateinit var pageSaveHelper: PageSaveHelper
|
|
|
|
|
|
|
|
|
|
private var thumbnailsAdapter: PageThumbnailAdapter? = null
|
|
|
|
|
private var spanResolver: GridSpanResolver? = null
|
|
|
|
|
private var scrollListener: ScrollListener? = null
|
|
|
|
|
private var selectionController: ListSelectionController? = null
|
|
|
|
|
|
|
|
|
|
private val spanSizeLookup = SpanSizeLookup()
|
|
|
|
|
|
|
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
|
|
|
super.onCreate(savedInstanceState)
|
|
|
|
|
pageSaveHelper = pageSaveHelperFactory.create(this)
|
|
|
|
|
combine(
|
|
|
|
|
parentViewModel.mangaDetails,
|
|
|
|
|
parentViewModel.readingState,
|
|
|
|
|
@ -83,6 +98,12 @@ class PagesFragment :
|
|
|
|
|
override fun onViewBindingCreated(binding: FragmentPagesBinding, savedInstanceState: Bundle?) {
|
|
|
|
|
super.onViewBindingCreated(binding, savedInstanceState)
|
|
|
|
|
spanResolver = GridSpanResolver(binding.root.resources)
|
|
|
|
|
selectionController = ListSelectionController(
|
|
|
|
|
appCompatDelegate = checkNotNull(findAppCompatDelegate()),
|
|
|
|
|
decoration = PagesSelectionDecoration(binding.root.context),
|
|
|
|
|
registryOwner = this,
|
|
|
|
|
callback = this,
|
|
|
|
|
)
|
|
|
|
|
thumbnailsAdapter = PageThumbnailAdapter(
|
|
|
|
|
coil = coil,
|
|
|
|
|
lifecycleOwner = viewLifecycleOwner,
|
|
|
|
|
@ -91,6 +112,7 @@ class PagesFragment :
|
|
|
|
|
viewModel.gridScale.observe(viewLifecycleOwner, ::onGridScaleChanged) // before rv initialization
|
|
|
|
|
with(binding.recyclerView) {
|
|
|
|
|
addItemDecoration(TypedListSpacingDecoration(context, false))
|
|
|
|
|
checkNotNull(selectionController).attachToRecyclerView(this)
|
|
|
|
|
adapter = thumbnailsAdapter
|
|
|
|
|
setHasFixedSize(true)
|
|
|
|
|
PagerNestedScrollHelper(this).bind(viewLifecycleOwner)
|
|
|
|
|
@ -103,6 +125,7 @@ class PagesFragment :
|
|
|
|
|
}
|
|
|
|
|
parentViewModel.isChaptersEmpty.observe(viewLifecycleOwner, ::onNoChaptersChanged)
|
|
|
|
|
viewModel.thumbnails.observe(viewLifecycleOwner, ::onThumbnailsChanged)
|
|
|
|
|
viewModel.onPageSaved.observeEvent(this, PagesSavedObserver(binding.recyclerView))
|
|
|
|
|
viewModel.onError.observeEvent(viewLifecycleOwner, SnackbarErrorObserver(binding.recyclerView, this))
|
|
|
|
|
viewModel.isLoading.observe(viewLifecycleOwner) { binding.progressBar.showOrHide(it) }
|
|
|
|
|
viewModel.isLoadingUp.observe(viewLifecycleOwner) { binding.progressBarTop.showOrHide(it) }
|
|
|
|
|
@ -113,6 +136,7 @@ class PagesFragment :
|
|
|
|
|
spanResolver = null
|
|
|
|
|
scrollListener = null
|
|
|
|
|
thumbnailsAdapter = null
|
|
|
|
|
selectionController = null
|
|
|
|
|
spanSizeLookup.invalidateCache()
|
|
|
|
|
super.onDestroyView()
|
|
|
|
|
}
|
|
|
|
|
@ -120,6 +144,9 @@ class PagesFragment :
|
|
|
|
|
override fun onWindowInsetsChanged(insets: Insets) = Unit
|
|
|
|
|
|
|
|
|
|
override fun onItemClick(item: PageThumbnail, view: View) {
|
|
|
|
|
if (selectionController?.onItemClick(item.page.id) == true) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
val listener = findParentCallback(ReaderNavigationCallback::class.java)
|
|
|
|
|
if (listener != null && listener.onPageSelected(item.page)) {
|
|
|
|
|
dismissParentDialog()
|
|
|
|
|
@ -133,6 +160,39 @@ class PagesFragment :
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override fun onItemLongClick(item: PageThumbnail, view: View): Boolean {
|
|
|
|
|
return selectionController?.onItemLongClick(view, item.page.id) ?: false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override fun onItemContextClick(item: PageThumbnail, view: View): Boolean {
|
|
|
|
|
return selectionController?.onItemContextClick(view, item.page.id) ?: false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override fun onSelectionChanged(controller: ListSelectionController, count: Int) {
|
|
|
|
|
viewBinding?.recyclerView?.invalidateItemDecorations()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override fun onCreateActionMode(
|
|
|
|
|
controller: ListSelectionController,
|
|
|
|
|
menuInflater: MenuInflater,
|
|
|
|
|
menu: Menu,
|
|
|
|
|
): Boolean {
|
|
|
|
|
menuInflater.inflate(R.menu.mode_pages, menu)
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override fun onActionItemClicked(controller: ListSelectionController, mode: ActionMode?, item: MenuItem): Boolean {
|
|
|
|
|
return when (item.itemId) {
|
|
|
|
|
R.id.action_save -> {
|
|
|
|
|
viewModel.savePages(pageSaveHelper, collectSelectedPages())
|
|
|
|
|
mode?.finish()
|
|
|
|
|
true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else -> false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private suspend fun onThumbnailsChanged(list: List<ListModel>) {
|
|
|
|
|
val adapter = thumbnailsAdapter ?: return
|
|
|
|
|
if (adapter.itemCount == 0) {
|
|
|
|
|
@ -172,6 +232,18 @@ class PagesFragment :
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun collectSelectedPages(): Set<ReaderPage> {
|
|
|
|
|
val checkedIds = selectionController?.peekCheckedIds() ?: return emptySet()
|
|
|
|
|
val items = thumbnailsAdapter?.items ?: return emptySet()
|
|
|
|
|
val result = ArraySet<ReaderPage>(checkedIds.size)
|
|
|
|
|
for (item in items) {
|
|
|
|
|
if (item is PageThumbnail && item.page.id in checkedIds) {
|
|
|
|
|
result.add(item.page)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private inner class ScrollListener : BoundsScrollListener(3, 3) {
|
|
|
|
|
|
|
|
|
|
override fun onScrolledToStart(recyclerView: RecyclerView) {
|
|
|
|
|
|