Implement long hold selection for Manga Chapters and library

Co-Authored-By: zhuoyang <zhuoyang@users.noreply.github.com>

Co-Authored-By: Jays2Kings <Jays2Kings@users.noreply.github.com>
This commit is contained in:
Jay 2019-12-05 21:50:36 -08:00 committed by arkon
parent e414b9edf1
commit 2d3bfa9a89
2 changed files with 60 additions and 10 deletions

View file

@ -1,11 +1,11 @@
package eu.kanade.tachiyomi.ui.library package eu.kanade.tachiyomi.ui.library
import android.content.Context import android.content.Context
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import android.util.AttributeSet import android.util.AttributeSet
import android.view.View import android.view.View
import android.widget.FrameLayout import android.widget.FrameLayout
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.SelectableAdapter import eu.davidea.flexibleadapter.SelectableAdapter
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
@ -18,8 +18,8 @@ import eu.kanade.tachiyomi.util.inflate
import eu.kanade.tachiyomi.util.plusAssign import eu.kanade.tachiyomi.util.plusAssign
import eu.kanade.tachiyomi.util.toast import eu.kanade.tachiyomi.util.toast
import eu.kanade.tachiyomi.widget.AutofitRecyclerView import eu.kanade.tachiyomi.widget.AutofitRecyclerView
import kotlinx.android.synthetic.main.chapters_controller.fast_scroller import kotlinx.android.synthetic.main.library_category.view.fast_scroller
import kotlinx.android.synthetic.main.library_category.view.* import kotlinx.android.synthetic.main.library_category.view.swipe_refresh
import rx.subscriptions.CompositeSubscription import rx.subscriptions.CompositeSubscription
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
@ -62,6 +62,8 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
*/ */
private var subscriptions = CompositeSubscription() private var subscriptions = CompositeSubscription()
private var lastClickPosition = -1
fun onCreate(controller: LibraryController) { fun onCreate(controller: LibraryController) {
this.controller = controller this.controller = controller
@ -174,6 +176,7 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
} }
is LibrarySelectionEvent.Unselected -> { is LibrarySelectionEvent.Unselected -> {
findAndToggleSelection(event.manga) findAndToggleSelection(event.manga)
if (adapter.indexOf(event.manga) != -1) lastClickPosition = -1
if (controller.selectedMangas.isEmpty()) { if (controller.selectedMangas.isEmpty()) {
adapter.mode = SelectableAdapter.Mode.SINGLE adapter.mode = SelectableAdapter.Mode.SINGLE
} }
@ -181,6 +184,7 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
is LibrarySelectionEvent.Cleared -> { is LibrarySelectionEvent.Cleared -> {
adapter.mode = SelectableAdapter.Mode.SINGLE adapter.mode = SelectableAdapter.Mode.SINGLE
adapter.clearSelection() adapter.clearSelection()
lastClickPosition = -1
} }
} }
} }
@ -204,10 +208,11 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
* @param position the position of the element clicked. * @param position the position of the element clicked.
* @return true if the item should be selected, false otherwise. * @return true if the item should be selected, false otherwise.
*/ */
override fun onItemClick(view: View, position: Int): Boolean { override fun onItemClick(view: View?, position: Int): Boolean {
// If the action mode is created and the position is valid, toggle the selection. // If the action mode is created and the position is valid, toggle the selection.
val item = adapter.getItem(position) ?: return false val item = adapter.getItem(position) ?: return false
if (adapter.mode == SelectableAdapter.Mode.MULTI) { if (adapter.mode == SelectableAdapter.Mode.MULTI) {
lastClickPosition = position
toggleSelection(position) toggleSelection(position)
return true return true
} else { } else {
@ -223,7 +228,15 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
*/ */
override fun onItemLongClick(position: Int) { override fun onItemLongClick(position: Int) {
controller.createActionModeIfNeeded() controller.createActionModeIfNeeded()
toggleSelection(position) when {
lastClickPosition == -1 -> setSelection(position)
lastClickPosition > position -> for (i in position until lastClickPosition)
setSelection(i)
lastClickPosition < position -> for (i in lastClickPosition + 1..position)
setSelection(i)
else -> setSelection(position)
}
lastClickPosition = position
} }
/** /**
@ -247,4 +260,17 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
controller.invalidateActionMode() controller.invalidateActionMode()
} }
/**
* Tells the presenter to set the selection for the given position.
*
* @param position the position to toggle.
*/
private fun setSelection(position: Int) {
val item = adapter.getItem(position) ?: return
controller.setSelection(item.manga, true)
controller.invalidateActionMode()
}
} }

View file

@ -55,6 +55,8 @@ class ChaptersController : NucleusController<ChaptersPresenter>(),
*/ */
private val selectedItems = mutableSetOf<ChapterItem>() private val selectedItems = mutableSetOf<ChapterItem>()
private var lastClickPosition = -1
init { init {
setHasOptionsMenu(true) setHasOptionsMenu(true)
setOptionsMenuHidden(true) setOptionsMenuHidden(true)
@ -184,8 +186,9 @@ class ChaptersController : NucleusController<ChaptersPresenter>(),
fun onNextChapters(chapters: List<ChapterItem>) { fun onNextChapters(chapters: List<ChapterItem>) {
// If the list is empty, fetch chapters from source if the conditions are met // If the list is empty, fetch chapters from source if the conditions are met
// We use presenter chapters instead because they are always unfiltered // We use presenter chapters instead because they are always unfiltered
if (presenter.chapters.isEmpty()) if (presenter.chapters.isEmpty()) {
initialFetchChapters() initialFetchChapters()
}
val adapter = adapter ?: return val adapter = adapter ?: return
adapter.updateDataSet(chapters) adapter.updateDataSet(chapters)
@ -242,10 +245,11 @@ class ChaptersController : NucleusController<ChaptersPresenter>(),
startActivity(intent) startActivity(intent)
} }
override fun onItemClick(view: View, position: Int): Boolean { override fun onItemClick(view: View?, position: Int): Boolean {
val adapter = adapter ?: return false val adapter = adapter ?: return false
val item = adapter.getItem(position) ?: return false val item = adapter.getItem(position) ?: return false
if (actionMode != null && adapter.mode == SelectableAdapter.Mode.MULTI) { if (actionMode != null && adapter.mode == SelectableAdapter.Mode.MULTI) {
lastClickPosition = position
toggleSelection(position) toggleSelection(position)
return true return true
} else { } else {
@ -256,7 +260,16 @@ class ChaptersController : NucleusController<ChaptersPresenter>(),
override fun onItemLongClick(position: Int) { override fun onItemLongClick(position: Int) {
createActionModeIfNeeded() createActionModeIfNeeded()
toggleSelection(position) when {
lastClickPosition == -1 -> setSelection(position)
lastClickPosition > position -> for (i in position until lastClickPosition)
setSelection(i)
lastClickPosition < position -> for (i in lastClickPosition + 1..position)
setSelection(i)
else -> setSelection(position)
}
lastClickPosition = position
adapter?.notifyDataSetChanged()
} }
// SELECTIONS & ACTION MODE // SELECTIONS & ACTION MODE
@ -265,6 +278,7 @@ class ChaptersController : NucleusController<ChaptersPresenter>(),
val adapter = adapter ?: return val adapter = adapter ?: return
val item = adapter.getItem(position) ?: return val item = adapter.getItem(position) ?: return
adapter.toggleSelection(position) adapter.toggleSelection(position)
adapter.notifyDataSetChanged()
if (adapter.isSelected(position)) { if (adapter.isSelected(position)) {
selectedItems.add(item) selectedItems.add(item)
} else { } else {
@ -273,6 +287,16 @@ class ChaptersController : NucleusController<ChaptersPresenter>(),
actionMode?.invalidate() actionMode?.invalidate()
} }
private fun setSelection(position: Int) {
val adapter = adapter ?: return
val item = adapter.getItem(position) ?: return
if (!adapter.isSelected(position)) {
adapter.toggleSelection(position)
selectedItems.add(item)
actionMode?.invalidate()
}
}
private fun getSelectedChapters(): List<ChapterItem> { private fun getSelectedChapters(): List<ChapterItem> {
val adapter = adapter ?: return emptyList() val adapter = adapter ?: return emptyList()
return adapter.selectedPositions.mapNotNull { adapter.getItem(it) } return adapter.selectedPositions.mapNotNull { adapter.getItem(it) }
@ -285,6 +309,7 @@ class ChaptersController : NucleusController<ChaptersPresenter>(),
} }
private fun destroyActionModeIfNeeded() { private fun destroyActionModeIfNeeded() {
lastClickPosition = -1
actionMode?.finish() actionMode?.finish()
} }
@ -373,7 +398,6 @@ class ChaptersController : NucleusController<ChaptersPresenter>(),
} }
} }
private fun showDeleteChaptersConfirmationDialog() { private fun showDeleteChaptersConfirmationDialog() {
DeleteChaptersDialog(this).showDialog(router) DeleteChaptersDialog(this).showDialog(router)
} }