Context menus
This commit is contained in:
@@ -3,6 +3,7 @@ package org.koitharu.kotatsu.bookmarks.ui
|
||||
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
|
||||
@@ -129,7 +130,11 @@ class AllBookmarksFragment :
|
||||
}
|
||||
|
||||
override fun onItemLongClick(item: Bookmark, view: View): Boolean {
|
||||
return selectionController?.onItemLongClick(item.pageId) ?: false
|
||||
return selectionController?.onItemLongClick(view, item.pageId) ?: false
|
||||
}
|
||||
|
||||
override fun onItemContextClick(item: Bookmark, view: View): Boolean {
|
||||
return selectionController?.onItemContextClick(view, item.pageId) ?: false
|
||||
}
|
||||
|
||||
override fun onRetryClick(error: Throwable) = Unit
|
||||
@@ -148,23 +153,23 @@ class AllBookmarksFragment :
|
||||
|
||||
override fun onCreateActionMode(
|
||||
controller: ListSelectionController,
|
||||
mode: ActionMode,
|
||||
menuInflater: MenuInflater,
|
||||
menu: Menu,
|
||||
): Boolean {
|
||||
mode.menuInflater.inflate(R.menu.mode_bookmarks, menu)
|
||||
menuInflater.inflate(R.menu.mode_bookmarks, menu)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onActionItemClicked(
|
||||
controller: ListSelectionController,
|
||||
mode: ActionMode,
|
||||
mode: ActionMode?,
|
||||
item: MenuItem,
|
||||
): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.action_remove -> {
|
||||
val ids = selectionController?.snapshot() ?: return false
|
||||
viewModel.removeBookmarks(ids)
|
||||
mode.finish()
|
||||
mode?.finish()
|
||||
true
|
||||
}
|
||||
|
||||
|
||||
@@ -22,10 +22,7 @@ fun bookmarkLargeAD(
|
||||
) = adapterDelegateViewBinding<Bookmark, ListModel, ItemBookmarkLargeBinding>(
|
||||
{ inflater, parent -> ItemBookmarkLargeBinding.inflate(inflater, parent, false) },
|
||||
) {
|
||||
val listener = AdapterDelegateClickListenerAdapter(this, clickListener)
|
||||
|
||||
binding.root.setOnClickListener(listener)
|
||||
binding.root.setOnLongClickListener(listener)
|
||||
AdapterDelegateClickListenerAdapter(this, clickListener).attach(itemView)
|
||||
|
||||
bind {
|
||||
binding.imageViewThumb.newImageRequest(lifecycleOwner, item.imageLoadData)?.run {
|
||||
|
||||
@@ -21,10 +21,7 @@ fun bookmarkListAD(
|
||||
) = adapterDelegateViewBinding<Bookmark, Bookmark, ItemBookmarkBinding>(
|
||||
{ inflater, parent -> ItemBookmarkBinding.inflate(inflater, parent, false) },
|
||||
) {
|
||||
val listener = AdapterDelegateClickListenerAdapter(this, clickListener)
|
||||
|
||||
binding.root.setOnClickListener(listener)
|
||||
binding.root.setOnLongClickListener(listener)
|
||||
AdapterDelegateClickListenerAdapter(this, clickListener).attach(itemView)
|
||||
|
||||
bind {
|
||||
binding.imageViewThumb.newImageRequest(lifecycleOwner, item.imageLoadData)?.run {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.koitharu.kotatsu.core.ui
|
||||
|
||||
import android.view.View
|
||||
|
||||
fun interface OnContextClickListenerCompat {
|
||||
|
||||
fun onContextClick(v: View): Boolean
|
||||
}
|
||||
@@ -3,18 +3,46 @@ package org.koitharu.kotatsu.core.ui.list
|
||||
import android.view.View
|
||||
import android.view.View.OnClickListener
|
||||
import android.view.View.OnLongClickListener
|
||||
import androidx.core.util.Function
|
||||
import com.hannesdorfmann.adapterdelegates4.dsl.AdapterDelegateViewBindingViewHolder
|
||||
import org.koitharu.kotatsu.core.ui.OnContextClickListenerCompat
|
||||
import org.koitharu.kotatsu.core.util.ext.setOnContextClickListenerCompat
|
||||
|
||||
class AdapterDelegateClickListenerAdapter<I>(
|
||||
class AdapterDelegateClickListenerAdapter<I, O>(
|
||||
private val adapterDelegate: AdapterDelegateViewBindingViewHolder<out I, *>,
|
||||
private val clickListener: OnListItemClickListener<I>,
|
||||
) : OnClickListener, OnLongClickListener {
|
||||
private val clickListener: OnListItemClickListener<O>,
|
||||
private val itemMapper: Function<I, O>,
|
||||
) : OnClickListener, OnLongClickListener, OnContextClickListenerCompat {
|
||||
|
||||
override fun onClick(v: View) {
|
||||
clickListener.onItemClick(adapterDelegate.item, v)
|
||||
clickListener.onItemClick(mappedItem(), v)
|
||||
}
|
||||
|
||||
override fun onLongClick(v: View): Boolean {
|
||||
return clickListener.onItemLongClick(adapterDelegate.item, v)
|
||||
return clickListener.onItemLongClick(mappedItem(), v)
|
||||
}
|
||||
|
||||
override fun onContextClick(v: View): Boolean {
|
||||
return clickListener.onItemContextClick(mappedItem(), v)
|
||||
}
|
||||
|
||||
private fun mappedItem(): O = itemMapper.apply(adapterDelegate.item)
|
||||
|
||||
fun attach(itemView: View) {
|
||||
itemView.setOnClickListener(this)
|
||||
itemView.setOnLongClickListener(this)
|
||||
itemView.setOnContextClickListenerCompat(this)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
operator fun <T> invoke(
|
||||
adapterDelegate: AdapterDelegateViewBindingViewHolder<out T, *>,
|
||||
clickListener: OnListItemClickListener<T>
|
||||
): AdapterDelegateClickListenerAdapter<T, T> = AdapterDelegateClickListenerAdapter(
|
||||
adapterDelegate = adapterDelegate,
|
||||
clickListener = clickListener,
|
||||
itemMapper = { x -> x },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,14 @@ package org.koitharu.kotatsu.core.ui.list
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.collection.LongSet
|
||||
import androidx.collection.longSetOf
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
@@ -29,18 +33,21 @@ class ListSelectionController(
|
||||
) : ActionMode.Callback, SavedStateRegistry.SavedStateProvider {
|
||||
|
||||
private var actionMode: ActionMode? = null
|
||||
private var focusedItemId: LongSet? = null
|
||||
|
||||
var useActionMode: Boolean = true
|
||||
|
||||
val count: Int
|
||||
get() = decoration.checkedItemsCount
|
||||
get() = if (focusedItemId != null) 1 else decoration.checkedItemsCount
|
||||
|
||||
init {
|
||||
registryOwner.lifecycle.addObserver(StateEventObserver())
|
||||
}
|
||||
|
||||
fun snapshot(): Set<Long> = peekCheckedIds().toSet()
|
||||
fun snapshot(): Set<Long> = (focusedItemId ?: peekCheckedIds()).toSet()
|
||||
|
||||
fun peekCheckedIds(): LongSet {
|
||||
return decoration.checkedItemsIds
|
||||
return focusedItemId ?: decoration.checkedItemsIds
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
@@ -52,6 +59,7 @@ class ListSelectionController(
|
||||
if (ids.isEmpty()) {
|
||||
return
|
||||
}
|
||||
startActionMode()
|
||||
decoration.checkAll(ids)
|
||||
notifySelectionChanged()
|
||||
}
|
||||
@@ -80,15 +88,42 @@ class ListSelectionController(
|
||||
return false
|
||||
}
|
||||
|
||||
fun onItemLongClick(id: Long): Boolean {
|
||||
return startActionMode()?.also {
|
||||
decoration.setItemIsChecked(id, true)
|
||||
notifySelectionChanged()
|
||||
} != null
|
||||
fun onItemLongClick(view: View, id: Long): Boolean {
|
||||
return if (useActionMode) {
|
||||
startSelection(id)
|
||||
} else {
|
||||
onItemContextClick(view, id)
|
||||
}
|
||||
}
|
||||
|
||||
fun onItemContextClick(view: View, id: Long): Boolean {
|
||||
focusedItemId = longSetOf(id)
|
||||
val menu = PopupMenu(view.context, view)
|
||||
callback.onCreateActionMode(this, menu.menuInflater, menu.menu)
|
||||
callback.onPrepareActionMode(this, null, menu.menu)
|
||||
menu.setForceShowIcon(true)
|
||||
if (menu.menu.hasVisibleItems()) {
|
||||
menu.setOnMenuItemClickListener { menuItem ->
|
||||
callback.onActionItemClicked(this, null, menuItem)
|
||||
}
|
||||
menu.setOnDismissListener {
|
||||
focusedItemId = null
|
||||
}
|
||||
menu.show()
|
||||
return true
|
||||
} else {
|
||||
focusedItemId = null
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
fun startSelection(id: Long): Boolean = startActionMode()?.also {
|
||||
decoration.setItemIsChecked(id, true)
|
||||
notifySelectionChanged()
|
||||
} != null
|
||||
|
||||
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
|
||||
return callback.onCreateActionMode(this, mode, menu)
|
||||
return callback.onCreateActionMode(this, mode.menuInflater, menu)
|
||||
}
|
||||
|
||||
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
|
||||
@@ -106,6 +141,7 @@ class ListSelectionController(
|
||||
}
|
||||
|
||||
private fun startActionMode(): ActionMode? {
|
||||
focusedItemId = null
|
||||
return actionMode ?: appCompatDelegate.startSupportActionMode(this).also {
|
||||
actionMode = it
|
||||
}
|
||||
@@ -134,14 +170,14 @@ class ListSelectionController(
|
||||
|
||||
fun onSelectionChanged(controller: ListSelectionController, count: Int)
|
||||
|
||||
fun onCreateActionMode(controller: ListSelectionController, mode: ActionMode, menu: Menu): Boolean
|
||||
fun onCreateActionMode(controller: ListSelectionController, menuInflater: MenuInflater, menu: Menu): Boolean
|
||||
|
||||
fun onPrepareActionMode(controller: ListSelectionController, mode: ActionMode, menu: Menu): Boolean {
|
||||
mode.title = controller.count.toString()
|
||||
fun onPrepareActionMode(controller: ListSelectionController, mode: ActionMode?, menu: Menu): Boolean {
|
||||
mode?.title = controller.count.toString()
|
||||
return true
|
||||
}
|
||||
|
||||
fun onActionItemClicked(controller: ListSelectionController, mode: ActionMode, item: MenuItem): Boolean
|
||||
fun onActionItemClicked(controller: ListSelectionController, mode: ActionMode?, item: MenuItem): Boolean
|
||||
|
||||
fun onDestroyActionMode(controller: ListSelectionController, mode: ActionMode) = Unit
|
||||
}
|
||||
|
||||
@@ -6,5 +6,7 @@ fun interface OnListItemClickListener<I> {
|
||||
|
||||
fun onItemClick(item: I, view: View)
|
||||
|
||||
fun onItemLongClick(item: I, view: View) = false
|
||||
fun onItemLongClick(item: I, view: View): Boolean = false
|
||||
|
||||
fun onItemContextClick(item: I, view: View): Boolean = onItemLongClick(item, view)
|
||||
}
|
||||
|
||||
@@ -4,11 +4,15 @@ import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.core.view.MenuProvider
|
||||
import org.koitharu.kotatsu.core.ui.OnContextClickListenerCompat
|
||||
import org.koitharu.kotatsu.core.util.ext.setOnContextClickListenerCompat
|
||||
|
||||
class PopupMenuMediator(
|
||||
private val provider: MenuProvider,
|
||||
) : View.OnLongClickListener, PopupMenu.OnMenuItemClickListener, PopupMenu.OnDismissListener {
|
||||
) : View.OnLongClickListener, OnContextClickListenerCompat, PopupMenu.OnMenuItemClickListener,
|
||||
PopupMenu.OnDismissListener {
|
||||
|
||||
override fun onContextClick(v: View): Boolean = onLongClick(v)
|
||||
|
||||
override fun onLongClick(v: View): Boolean {
|
||||
val menu = PopupMenu(v.context, v)
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.google.android.material.progressindicator.BaseProgressIndicator
|
||||
import com.google.android.material.slider.RangeSlider
|
||||
import com.google.android.material.slider.Slider
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import org.koitharu.kotatsu.core.ui.OnContextClickListenerCompat
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
fun View.hasGlobalPoint(x: Int, y: Int): Boolean {
|
||||
@@ -153,9 +154,9 @@ fun BaseProgressIndicator<*>.showOrHide(value: Boolean) {
|
||||
}
|
||||
}
|
||||
|
||||
fun View.setOnContextClickListenerCompat(listener: View.OnLongClickListener) {
|
||||
fun View.setOnContextClickListenerCompat(listener: OnContextClickListenerCompat) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
setOnContextClickListener(listener::onLongClick)
|
||||
setOnContextClickListener(listener::onContextClick)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ import org.koitharu.kotatsu.core.parser.MangaIntent
|
||||
import org.koitharu.kotatsu.core.parser.favicon.faviconUri
|
||||
import org.koitharu.kotatsu.core.ui.BaseActivity
|
||||
import org.koitharu.kotatsu.core.ui.BaseListAdapter
|
||||
import org.koitharu.kotatsu.core.ui.OnContextClickListenerCompat
|
||||
import org.koitharu.kotatsu.core.ui.image.ChipIconTarget
|
||||
import org.koitharu.kotatsu.core.ui.image.CoverSizeResolver
|
||||
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
|
||||
@@ -114,7 +115,8 @@ class DetailsActivity :
|
||||
BaseActivity<ActivityDetailsBinding>(),
|
||||
View.OnClickListener,
|
||||
View.OnLongClickListener, PopupMenu.OnMenuItemClickListener, View.OnLayoutChangeListener,
|
||||
ViewTreeObserver.OnDrawListener, ChipsView.OnChipClickListener, OnListItemClickListener<Bookmark> {
|
||||
ViewTreeObserver.OnDrawListener, ChipsView.OnChipClickListener, OnListItemClickListener<Bookmark>,
|
||||
OnContextClickListenerCompat {
|
||||
|
||||
@Inject
|
||||
lateinit var shortcutManager: AppShortcutManager
|
||||
@@ -291,6 +293,8 @@ class DetailsActivity :
|
||||
startActivity(MangaListActivity.newIntent(this, tag.source, MangaListFilter(tags = setOf(tag))))
|
||||
}
|
||||
|
||||
override fun onContextClick(v: View): Boolean = onLongClick(v)
|
||||
|
||||
override fun onLongClick(v: View): Boolean = when (v.id) {
|
||||
R.id.button_read -> {
|
||||
val menu = PopupMenu(v.context, v)
|
||||
|
||||
@@ -18,9 +18,7 @@ fun chapterGridItemAD(
|
||||
on = { item, _, _ -> item is ChapterListItem && item.isGrid },
|
||||
) {
|
||||
|
||||
val eventListener = AdapterDelegateClickListenerAdapter(this, clickListener)
|
||||
itemView.setOnClickListener(eventListener)
|
||||
itemView.setOnLongClickListener(eventListener)
|
||||
AdapterDelegateClickListenerAdapter(this, clickListener).attach(itemView)
|
||||
|
||||
bind { payloads ->
|
||||
if (payloads.isEmpty()) {
|
||||
|
||||
@@ -22,9 +22,7 @@ fun chapterListItemAD(
|
||||
on = { item, _, _ -> item is ChapterListItem && !item.isGrid },
|
||||
) {
|
||||
|
||||
val eventListener = AdapterDelegateClickListenerAdapter(this, clickListener)
|
||||
itemView.setOnClickListener(eventListener)
|
||||
itemView.setOnLongClickListener(eventListener)
|
||||
AdapterDelegateClickListenerAdapter(this, clickListener).attach(itemView)
|
||||
|
||||
bind {
|
||||
binding.textViewTitle.text = item.chapter.name
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.koitharu.kotatsu.details.ui.pager.bookmarks
|
||||
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
|
||||
@@ -133,7 +134,11 @@ class BookmarksFragment : BaseFragment<FragmentMangaBookmarksBinding>(),
|
||||
}
|
||||
|
||||
override fun onItemLongClick(item: Bookmark, view: View): Boolean {
|
||||
return selectionController?.onItemLongClick(item.pageId) ?: false
|
||||
return selectionController?.onItemLongClick(view, item.pageId) ?: false
|
||||
}
|
||||
|
||||
override fun onItemContextClick(item: Bookmark, view: View): Boolean {
|
||||
return selectionController?.onItemContextClick(view, item.pageId) ?: false
|
||||
}
|
||||
|
||||
override fun onSelectionChanged(controller: ListSelectionController, count: Int) {
|
||||
@@ -142,23 +147,23 @@ class BookmarksFragment : BaseFragment<FragmentMangaBookmarksBinding>(),
|
||||
|
||||
override fun onCreateActionMode(
|
||||
controller: ListSelectionController,
|
||||
mode: ActionMode,
|
||||
menuInflater: MenuInflater,
|
||||
menu: Menu,
|
||||
): Boolean {
|
||||
mode.menuInflater.inflate(R.menu.mode_bookmarks, menu)
|
||||
menuInflater.inflate(R.menu.mode_bookmarks, menu)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onActionItemClicked(
|
||||
controller: ListSelectionController,
|
||||
mode: ActionMode,
|
||||
mode: ActionMode?,
|
||||
item: MenuItem,
|
||||
): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.action_remove -> {
|
||||
val ids = selectionController?.snapshot() ?: return false
|
||||
viewModel.removeBookmarks(ids)
|
||||
mode.finish()
|
||||
mode?.finish()
|
||||
true
|
||||
}
|
||||
|
||||
|
||||
@@ -116,7 +116,11 @@ class ChaptersFragment :
|
||||
}
|
||||
|
||||
override fun onItemLongClick(item: ChapterListItem, view: View): Boolean {
|
||||
return selectionController?.onItemLongClick(item.chapter.id) ?: false
|
||||
return selectionController?.onItemLongClick(view, item.chapter.id) ?: false
|
||||
}
|
||||
|
||||
override fun onItemContextClick(item: ChapterListItem, view: View): Boolean {
|
||||
return selectionController?.onItemContextClick(view, item.chapter.id) ?: false
|
||||
}
|
||||
|
||||
override fun onWindowInsetsChanged(insets: Insets) = Unit
|
||||
@@ -149,7 +153,7 @@ class ChaptersFragment :
|
||||
items?.indexOfFirst(predicate) ?: -1
|
||||
}
|
||||
if (position >= 0) {
|
||||
selectionController?.onItemLongClick(chapterId)
|
||||
selectionController?.startSelection(chapterId)
|
||||
val lm = (viewBinding?.recyclerViewChapters?.layoutManager as? LinearLayoutManager)
|
||||
if (lm != null) {
|
||||
val offset = resources.getDimensionPixelOffset(R.dimen.chapter_list_item_height)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.koitharu.kotatsu.details.ui.pager.chapters
|
||||
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
@@ -19,12 +20,16 @@ class ChaptersSelectionCallback(
|
||||
recyclerView: RecyclerView,
|
||||
) : BaseListSelectionCallback(recyclerView) {
|
||||
|
||||
override fun onCreateActionMode(controller: ListSelectionController, mode: ActionMode, menu: Menu): Boolean {
|
||||
mode.menuInflater.inflate(R.menu.mode_chapters, menu)
|
||||
override fun onCreateActionMode(
|
||||
controller: ListSelectionController,
|
||||
menuInflater: MenuInflater,
|
||||
menu: Menu
|
||||
): Boolean {
|
||||
menuInflater.inflate(R.menu.mode_chapters, menu)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPrepareActionMode(controller: ListSelectionController, mode: ActionMode, menu: Menu): Boolean {
|
||||
override fun onPrepareActionMode(controller: ListSelectionController, mode: ActionMode?, menu: Menu): Boolean {
|
||||
val selectedIds = controller.peekCheckedIds()
|
||||
val allItems = viewModel.chapters.value
|
||||
val items = allItems.withIndex().filter { it.value.chapter.id in selectedIds }
|
||||
@@ -38,7 +43,7 @@ class ChaptersSelectionCallback(
|
||||
menu.findItem(R.id.action_delete).isVisible = canDelete
|
||||
menu.findItem(R.id.action_select_all).isVisible = items.size < allItems.size
|
||||
menu.findItem(R.id.action_mark_current).isVisible = items.size == 1
|
||||
mode.title = items.size.toString()
|
||||
mode?.title = items.size.toString()
|
||||
var hasGap = false
|
||||
for (i in 0 until items.size - 1) {
|
||||
if (items[i].index + 1 != items[i + 1].index) {
|
||||
@@ -50,11 +55,11 @@ class ChaptersSelectionCallback(
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onActionItemClicked(controller: ListSelectionController, mode: ActionMode, item: MenuItem): Boolean {
|
||||
override fun onActionItemClicked(controller: ListSelectionController, mode: ActionMode?, item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.action_save -> {
|
||||
viewModel.download(controller.snapshot())
|
||||
mode.finish()
|
||||
mode?.finish()
|
||||
true
|
||||
}
|
||||
|
||||
@@ -73,7 +78,7 @@ class ChaptersSelectionCallback(
|
||||
).show()
|
||||
}
|
||||
}
|
||||
mode.finish()
|
||||
mode?.finish()
|
||||
true
|
||||
}
|
||||
|
||||
@@ -112,7 +117,7 @@ class ChaptersSelectionCallback(
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
mode.finish()
|
||||
mode?.finish()
|
||||
true
|
||||
}
|
||||
|
||||
|
||||
@@ -32,9 +32,7 @@ fun pageThumbnailAD(
|
||||
height = (gridWidth / 13f * 18f).toInt(),
|
||||
)
|
||||
|
||||
val clickListenerAdapter = AdapterDelegateClickListenerAdapter(this, clickListener)
|
||||
binding.root.setOnClickListener(clickListenerAdapter)
|
||||
binding.root.setOnLongClickListener(clickListenerAdapter)
|
||||
AdapterDelegateClickListenerAdapter(this, clickListener).attach(itemView)
|
||||
|
||||
bind {
|
||||
val data: Any = item.page.preview?.takeUnless { it.isEmpty() } ?: item.page.toMangaPage()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.koitharu.kotatsu.details.ui.related
|
||||
|
||||
import android.view.Menu
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import android.view.MenuInflater
|
||||
import androidx.fragment.app.viewModels
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.koitharu.kotatsu.R
|
||||
@@ -16,9 +16,13 @@ class RelatedListFragment : MangaListFragment() {
|
||||
|
||||
override fun onScrolledToEnd() = Unit
|
||||
|
||||
override fun onCreateActionMode(controller: ListSelectionController, mode: ActionMode, menu: Menu): Boolean {
|
||||
mode.menuInflater.inflate(R.menu.mode_remote, menu)
|
||||
return super.onCreateActionMode(controller, mode, menu)
|
||||
override fun onCreateActionMode(
|
||||
controller: ListSelectionController,
|
||||
menuInflater: MenuInflater,
|
||||
menu: Menu
|
||||
): Boolean {
|
||||
menuInflater.inflate(R.menu.mode_remote, menu)
|
||||
return super.onCreateActionMode(controller, menuInflater, menu)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.download.ui.list
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.activity.viewModels
|
||||
@@ -87,7 +88,11 @@ class DownloadsActivity : BaseActivity<ActivityDownloadsBinding>(),
|
||||
}
|
||||
|
||||
override fun onItemLongClick(item: DownloadItemModel, view: View): Boolean {
|
||||
return selectionController.onItemLongClick(item.id.mostSignificantBits)
|
||||
return selectionController.onItemLongClick(view, item.id.mostSignificantBits)
|
||||
}
|
||||
|
||||
override fun onItemContextClick(item: DownloadItemModel, view: View): Boolean {
|
||||
return selectionController.onItemContextClick(view, item.id.mostSignificantBits)
|
||||
}
|
||||
|
||||
override fun onExpandClick(item: DownloadItemModel) {
|
||||
@@ -120,34 +125,38 @@ class DownloadsActivity : BaseActivity<ActivityDownloadsBinding>(),
|
||||
viewBinding.recyclerView.invalidateItemDecorations()
|
||||
}
|
||||
|
||||
override fun onCreateActionMode(controller: ListSelectionController, mode: ActionMode, menu: Menu): Boolean {
|
||||
mode.menuInflater.inflate(R.menu.mode_downloads, menu)
|
||||
override fun onCreateActionMode(
|
||||
controller: ListSelectionController,
|
||||
menuInflater: MenuInflater,
|
||||
menu: Menu
|
||||
): Boolean {
|
||||
menuInflater.inflate(R.menu.mode_downloads, menu)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onActionItemClicked(controller: ListSelectionController, mode: ActionMode, item: MenuItem): Boolean {
|
||||
override fun onActionItemClicked(controller: ListSelectionController, mode: ActionMode?, item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.action_resume -> {
|
||||
viewModel.resume(controller.snapshot())
|
||||
mode.finish()
|
||||
mode?.finish()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.action_pause -> {
|
||||
viewModel.pause(controller.snapshot())
|
||||
mode.finish()
|
||||
mode?.finish()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.action_cancel -> {
|
||||
viewModel.cancel(controller.snapshot())
|
||||
mode.finish()
|
||||
mode?.finish()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.action_remove -> {
|
||||
viewModel.remove(controller.snapshot())
|
||||
mode.finish()
|
||||
mode?.finish()
|
||||
true
|
||||
}
|
||||
|
||||
@@ -160,7 +169,7 @@ class DownloadsActivity : BaseActivity<ActivityDownloadsBinding>(),
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPrepareActionMode(controller: ListSelectionController, mode: ActionMode, menu: Menu): Boolean {
|
||||
override fun onPrepareActionMode(controller: ListSelectionController, mode: ActionMode?, menu: Menu): Boolean {
|
||||
val snapshot = viewModel.snapshot(controller.peekCheckedIds())
|
||||
var canPause = true
|
||||
var canResume = true
|
||||
|
||||
@@ -7,6 +7,7 @@ import android.os.Build
|
||||
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
|
||||
@@ -147,7 +148,11 @@ class ExploreFragment :
|
||||
}
|
||||
|
||||
override fun onItemLongClick(item: MangaSourceItem, view: View): Boolean {
|
||||
return sourceSelectionController?.onItemLongClick(item.id) ?: false
|
||||
return sourceSelectionController?.onItemLongClick(view, item.id) ?: false
|
||||
}
|
||||
|
||||
override fun onItemContextClick(item: MangaSourceItem, view: View): Boolean {
|
||||
return sourceSelectionController?.onItemContextClick(view, item.id) ?: false
|
||||
}
|
||||
|
||||
override fun onRetryClick(error: Throwable) = Unit
|
||||
@@ -160,12 +165,16 @@ class ExploreFragment :
|
||||
viewBinding?.recyclerView?.invalidateItemDecorations()
|
||||
}
|
||||
|
||||
override fun onCreateActionMode(controller: ListSelectionController, mode: ActionMode, menu: Menu): Boolean {
|
||||
mode.menuInflater.inflate(R.menu.mode_source, menu)
|
||||
override fun onCreateActionMode(
|
||||
controller: ListSelectionController,
|
||||
menuInflater: MenuInflater,
|
||||
menu: Menu
|
||||
): Boolean {
|
||||
menuInflater.inflate(R.menu.mode_source, menu)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPrepareActionMode(controller: ListSelectionController, mode: ActionMode, menu: Menu): Boolean {
|
||||
override fun onPrepareActionMode(controller: ListSelectionController, mode: ActionMode?, menu: Menu): Boolean {
|
||||
val selectedSources = viewModel.sourcesSnapshot(controller.peekCheckedIds())
|
||||
val isSingleSelection = selectedSources.size == 1
|
||||
menu.findItem(R.id.action_settings).isVisible = isSingleSelection
|
||||
@@ -177,7 +186,7 @@ class ExploreFragment :
|
||||
return super.onPrepareActionMode(controller, mode, menu)
|
||||
}
|
||||
|
||||
override fun onActionItemClicked(controller: ListSelectionController, mode: ActionMode, item: MenuItem): Boolean {
|
||||
override fun onActionItemClicked(controller: ListSelectionController, mode: ActionMode?, item: MenuItem): Boolean {
|
||||
val selectedSources = viewModel.sourcesSnapshot(controller.peekCheckedIds())
|
||||
if (selectedSources.isEmpty()) {
|
||||
return false
|
||||
@@ -186,35 +195,35 @@ class ExploreFragment :
|
||||
R.id.action_settings -> {
|
||||
val source = selectedSources.singleOrNull() ?: return false
|
||||
startActivity(SettingsActivity.newSourceSettingsIntent(requireContext(), source))
|
||||
mode.finish()
|
||||
mode?.finish()
|
||||
}
|
||||
|
||||
R.id.action_disable -> {
|
||||
viewModel.disableSources(selectedSources)
|
||||
mode.finish()
|
||||
mode?.finish()
|
||||
}
|
||||
|
||||
R.id.action_delete -> {
|
||||
selectedSources.forEach {
|
||||
(it.mangaSource as? ExternalMangaSource)?.let { uninstallExternalSource(it) }
|
||||
}
|
||||
mode.finish()
|
||||
mode?.finish()
|
||||
}
|
||||
|
||||
R.id.action_shortcut -> {
|
||||
val source = selectedSources.singleOrNull() ?: return false
|
||||
viewModel.requestPinShortcut(source)
|
||||
mode.finish()
|
||||
mode?.finish()
|
||||
}
|
||||
|
||||
R.id.action_pin -> {
|
||||
viewModel.setSourcesPinned(selectedSources, isPinned = true)
|
||||
mode.finish()
|
||||
mode?.finish()
|
||||
}
|
||||
|
||||
R.id.action_unpin -> {
|
||||
viewModel.setSourcesPinned(selectedSources, isPinned = false)
|
||||
mode.finish()
|
||||
mode?.finish()
|
||||
}
|
||||
|
||||
else -> return false
|
||||
|
||||
@@ -20,7 +20,6 @@ import org.koitharu.kotatsu.core.util.ext.drawableStart
|
||||
import org.koitharu.kotatsu.core.util.ext.enqueueWith
|
||||
import org.koitharu.kotatsu.core.util.ext.newImageRequest
|
||||
import org.koitharu.kotatsu.core.util.ext.recyclerView
|
||||
import org.koitharu.kotatsu.core.util.ext.setOnContextClickListenerCompat
|
||||
import org.koitharu.kotatsu.core.util.ext.setProgressIcon
|
||||
import org.koitharu.kotatsu.core.util.ext.source
|
||||
import org.koitharu.kotatsu.core.util.ext.textAndVisible
|
||||
@@ -117,13 +116,9 @@ fun exploreSourceListItemAD(
|
||||
on = { item, _, _ -> item is MangaSourceItem && !item.isGrid },
|
||||
) {
|
||||
|
||||
val eventListener = AdapterDelegateClickListenerAdapter(this, listener)
|
||||
AdapterDelegateClickListenerAdapter(this, listener).attach(itemView)
|
||||
val iconPinned = ContextCompat.getDrawable(context, R.drawable.ic_pin_small)
|
||||
|
||||
binding.root.setOnClickListener(eventListener)
|
||||
binding.root.setOnLongClickListener(eventListener)
|
||||
binding.root.setOnContextClickListenerCompat(eventListener)
|
||||
|
||||
bind {
|
||||
binding.textViewTitle.text = item.source.getTitle(context)
|
||||
binding.textViewTitle.drawableStart = if (item.source.isPinned) iconPinned else null
|
||||
@@ -154,13 +149,9 @@ fun exploreSourceGridItemAD(
|
||||
on = { item, _, _ -> item is MangaSourceItem && item.isGrid },
|
||||
) {
|
||||
|
||||
val eventListener = AdapterDelegateClickListenerAdapter(this, listener)
|
||||
AdapterDelegateClickListenerAdapter(this, listener).attach(itemView)
|
||||
val iconPinned = ContextCompat.getDrawable(context, R.drawable.ic_pin_small)
|
||||
|
||||
binding.root.setOnClickListener(eventListener)
|
||||
binding.root.setOnLongClickListener(eventListener)
|
||||
binding.root.setOnContextClickListenerCompat(eventListener)
|
||||
|
||||
bind {
|
||||
binding.textViewTitle.text = item.source.getTitle(context)
|
||||
binding.textViewTitle.drawableStart = if (item.source.isPinned) iconPinned else null
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.koitharu.kotatsu.favourites.ui.categories
|
||||
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
@@ -17,12 +18,16 @@ class CategoriesSelectionCallback(
|
||||
recyclerView.invalidateItemDecorations()
|
||||
}
|
||||
|
||||
override fun onCreateActionMode(controller: ListSelectionController, mode: ActionMode, menu: Menu): Boolean {
|
||||
mode.menuInflater.inflate(R.menu.mode_category, menu)
|
||||
override fun onCreateActionMode(
|
||||
controller: ListSelectionController,
|
||||
menuInflater: MenuInflater,
|
||||
menu: Menu
|
||||
): Boolean {
|
||||
menuInflater.inflate(R.menu.mode_category, menu)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPrepareActionMode(controller: ListSelectionController, mode: ActionMode, menu: Menu): Boolean {
|
||||
override fun onPrepareActionMode(controller: ListSelectionController, mode: ActionMode?, menu: Menu): Boolean {
|
||||
val categories = viewModel.getCategories(controller.peekCheckedIds())
|
||||
var canShow = categories.isNotEmpty()
|
||||
var canHide = canShow
|
||||
@@ -35,11 +40,11 @@ class CategoriesSelectionCallback(
|
||||
}
|
||||
menu.findItem(R.id.action_show)?.isVisible = canShow
|
||||
menu.findItem(R.id.action_hide)?.isVisible = canHide
|
||||
mode.title = controller.count.toString()
|
||||
mode?.title = controller.count.toString()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onActionItemClicked(controller: ListSelectionController, mode: ActionMode, item: MenuItem): Boolean {
|
||||
override fun onActionItemClicked(controller: ListSelectionController, mode: ActionMode?, item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
/*R.id.action_view -> {
|
||||
val id = controller.peekCheckedIds().singleOrNull() ?: return false
|
||||
@@ -53,13 +58,13 @@ class CategoriesSelectionCallback(
|
||||
|
||||
R.id.action_show -> {
|
||||
viewModel.setIsVisible(controller.snapshot(), true)
|
||||
mode.finish()
|
||||
mode?.finish()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.action_hide -> {
|
||||
viewModel.setIsVisible(controller.snapshot(), false)
|
||||
mode.finish()
|
||||
mode?.finish()
|
||||
true
|
||||
}
|
||||
|
||||
@@ -72,7 +77,7 @@ class CategoriesSelectionCallback(
|
||||
}
|
||||
}
|
||||
|
||||
private fun confirmDeleteCategories(ids: Set<Long>, mode: ActionMode) {
|
||||
private fun confirmDeleteCategories(ids: Set<Long>, mode: ActionMode?) {
|
||||
buildAlertDialog(recyclerView.context, isCentered = true) {
|
||||
setMessage(R.string.categories_delete_confirm)
|
||||
setTitle(R.string.remove_category)
|
||||
@@ -80,7 +85,7 @@ class CategoriesSelectionCallback(
|
||||
setNegativeButton(android.R.string.cancel, null)
|
||||
setPositiveButton(R.string.remove) { _, _ ->
|
||||
viewModel.deleteCategories(ids)
|
||||
mode.finish()
|
||||
mode?.finish()
|
||||
}
|
||||
}.show()
|
||||
}
|
||||
|
||||
@@ -98,7 +98,11 @@ class FavouriteCategoriesActivity :
|
||||
}
|
||||
|
||||
override fun onItemLongClick(item: FavouriteCategory?, view: View): Boolean {
|
||||
return item != null && selectionController.onItemLongClick(item.id)
|
||||
return item != null && selectionController.onItemLongClick(view, item.id)
|
||||
}
|
||||
|
||||
override fun onItemContextClick(item: FavouriteCategory?, view: View): Boolean {
|
||||
return item != null && selectionController.onItemContextClick(view, item.id)
|
||||
}
|
||||
|
||||
override fun onSupportActionModeStarted(mode: ActionMode) {
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.favourites.ui.list
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.appcompat.view.ActionMode
|
||||
@@ -52,27 +53,32 @@ class FavouritesListFragment : MangaListFragment(), PopupMenu.OnMenuItemClickLis
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onCreateActionMode(controller: ListSelectionController, mode: ActionMode, menu: Menu): Boolean {
|
||||
mode.menuInflater.inflate(R.menu.mode_favourites, menu)
|
||||
return super.onCreateActionMode(controller, mode, menu)
|
||||
override fun onCreateActionMode(
|
||||
controller: ListSelectionController,
|
||||
menuInflater: MenuInflater,
|
||||
menu: Menu
|
||||
): Boolean {
|
||||
menuInflater.inflate(R.menu.mode_favourites, menu)
|
||||
return super.onCreateActionMode(controller, menuInflater, menu)
|
||||
}
|
||||
|
||||
override fun onActionItemClicked(controller: ListSelectionController, mode: ActionMode, item: MenuItem): Boolean {
|
||||
override fun onActionItemClicked(controller: ListSelectionController, mode: ActionMode?, item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.action_remove -> {
|
||||
viewModel.removeFromFavourites(selectedItemsIds)
|
||||
mode.finish()
|
||||
mode?.finish()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.action_mark_current -> {
|
||||
val itemsSnapshot = selectedItems
|
||||
MaterialAlertDialogBuilder(context ?: return false)
|
||||
.setTitle(item.title)
|
||||
.setMessage(R.string.mark_as_completed_prompt)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
viewModel.markAsRead(selectedItems)
|
||||
mode.finish()
|
||||
viewModel.markAsRead(itemsSnapshot)
|
||||
mode?.finish()
|
||||
}.show()
|
||||
true
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.history.ui
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.fragment.app.viewModels
|
||||
@@ -34,28 +35,33 @@ class HistoryListFragment : MangaListFragment() {
|
||||
|
||||
override fun onEmptyActionClick() = viewModel.clearFilter()
|
||||
|
||||
override fun onCreateActionMode(controller: ListSelectionController, mode: ActionMode, menu: Menu): Boolean {
|
||||
mode.menuInflater.inflate(R.menu.mode_history, menu)
|
||||
return super.onCreateActionMode(controller, mode, menu)
|
||||
override fun onCreateActionMode(
|
||||
controller: ListSelectionController,
|
||||
menuInflater: MenuInflater,
|
||||
menu: Menu
|
||||
): Boolean {
|
||||
menuInflater.inflate(R.menu.mode_history, menu)
|
||||
return super.onCreateActionMode(controller, menuInflater, menu)
|
||||
}
|
||||
|
||||
override fun onActionItemClicked(controller: ListSelectionController, mode: ActionMode, item: MenuItem): Boolean {
|
||||
override fun onActionItemClicked(controller: ListSelectionController, mode: ActionMode?, item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.action_remove -> {
|
||||
viewModel.removeFromHistory(selectedItemsIds)
|
||||
mode.finish()
|
||||
mode?.finish()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.action_mark_current -> {
|
||||
val itemsSnapshot = selectedItems
|
||||
buildAlertDialog(context ?: return false, isCentered = true) {
|
||||
setTitle(item.title)
|
||||
setIcon(item.icon)
|
||||
setMessage(R.string.mark_as_completed_prompt)
|
||||
setNegativeButton(android.R.string.cancel, null)
|
||||
setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
viewModel.markAsRead(selectedItems)
|
||||
mode.finish()
|
||||
viewModel.markAsRead(itemsSnapshot)
|
||||
mode?.finish()
|
||||
}
|
||||
}.show()
|
||||
true
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.koitharu.kotatsu.list.ui
|
||||
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
|
||||
@@ -11,7 +12,6 @@ import androidx.annotation.CallSuper
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.collection.ArraySet
|
||||
import androidx.core.graphics.Insets
|
||||
import androidx.core.view.isNotEmpty
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
@@ -153,7 +153,11 @@ abstract class MangaListFragment :
|
||||
}
|
||||
|
||||
override fun onItemLongClick(item: Manga, view: View): Boolean {
|
||||
return selectionController?.onItemLongClick(item.id) ?: false
|
||||
return selectionController?.onItemLongClick(view, item.id) ?: false
|
||||
}
|
||||
|
||||
override fun onItemContextClick(item: Manga, view: View): Boolean {
|
||||
return selectionController?.onItemContextClick(view, item.id) ?: false
|
||||
}
|
||||
|
||||
override fun onReadClick(manga: Manga, view: View) {
|
||||
@@ -280,18 +284,22 @@ abstract class MangaListFragment :
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
override fun onPrepareActionMode(controller: ListSelectionController, mode: ActionMode, menu: Menu): Boolean {
|
||||
override fun onPrepareActionMode(controller: ListSelectionController, mode: ActionMode?, menu: Menu): Boolean {
|
||||
val hasNoLocal = selectedItems.none { it.isLocal }
|
||||
menu.findItem(R.id.action_save)?.isVisible = hasNoLocal
|
||||
menu.findItem(R.id.action_fix)?.isVisible = hasNoLocal
|
||||
return super.onPrepareActionMode(controller, mode, menu)
|
||||
}
|
||||
|
||||
override fun onCreateActionMode(controller: ListSelectionController, mode: ActionMode, menu: Menu): Boolean {
|
||||
return menu.isNotEmpty()
|
||||
override fun onCreateActionMode(
|
||||
controller: ListSelectionController,
|
||||
menuInflater: MenuInflater,
|
||||
menu: Menu
|
||||
): Boolean {
|
||||
return menu.hasVisibleItems()
|
||||
}
|
||||
|
||||
override fun onActionItemClicked(controller: ListSelectionController, mode: ActionMode, item: MenuItem): Boolean {
|
||||
override fun onActionItemClicked(controller: ListSelectionController, mode: ActionMode?, item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.action_select_all -> {
|
||||
val ids = listAdapter?.items?.mapNotNull {
|
||||
@@ -303,31 +311,32 @@ abstract class MangaListFragment :
|
||||
|
||||
R.id.action_share -> {
|
||||
ShareHelper(requireContext()).shareMangaLinks(selectedItems)
|
||||
mode.finish()
|
||||
mode?.finish()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.action_favourite -> {
|
||||
FavoriteSheet.show(getChildFragmentManager(), selectedItems)
|
||||
mode.finish()
|
||||
mode?.finish()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.action_save -> {
|
||||
viewModel.download(selectedItems)
|
||||
mode.finish()
|
||||
mode?.finish()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.action_fix -> {
|
||||
val itemsSnapshot = selectedItemsIds
|
||||
buildAlertDialog(context ?: return false, isCentered = true) {
|
||||
setTitle(item.title)
|
||||
setIcon(item.icon)
|
||||
setMessage(R.string.manga_fix_prompt)
|
||||
setNegativeButton(android.R.string.cancel, null)
|
||||
setPositiveButton(R.string.fix) { _, _ ->
|
||||
AutoFixService.start(context, selectedItemsIds)
|
||||
mode.finish()
|
||||
AutoFixService.start(context, itemsSnapshot)
|
||||
mode?.finish()
|
||||
}
|
||||
}.show()
|
||||
true
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.koitharu.kotatsu.list.ui.adapter
|
||||
|
||||
import android.view.View
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import coil.ImageLoader
|
||||
@@ -8,11 +7,11 @@ import com.google.android.material.badge.BadgeDrawable
|
||||
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
||||
import org.koitharu.kotatsu.core.ui.image.CoverSizeResolver
|
||||
import org.koitharu.kotatsu.core.ui.image.TrimTransformation
|
||||
import org.koitharu.kotatsu.core.ui.list.AdapterDelegateClickListenerAdapter
|
||||
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.core.util.ext.defaultPlaceholders
|
||||
import org.koitharu.kotatsu.core.util.ext.enqueueWith
|
||||
import org.koitharu.kotatsu.core.util.ext.newImageRequest
|
||||
import org.koitharu.kotatsu.core.util.ext.setOnContextClickListenerCompat
|
||||
import org.koitharu.kotatsu.core.util.ext.source
|
||||
import org.koitharu.kotatsu.databinding.ItemMangaGridBinding
|
||||
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback.Companion.PAYLOAD_PROGRESS_CHANGED
|
||||
@@ -31,13 +30,7 @@ fun mangaGridItemAD(
|
||||
) {
|
||||
var badge: BadgeDrawable? = null
|
||||
|
||||
val eventListener = object : View.OnClickListener, View.OnLongClickListener {
|
||||
override fun onClick(v: View) = clickListener.onItemClick(item.manga, v)
|
||||
override fun onLongClick(v: View): Boolean = clickListener.onItemLongClick(item.manga, v)
|
||||
}
|
||||
itemView.setOnClickListener(eventListener)
|
||||
itemView.setOnLongClickListener(eventListener)
|
||||
itemView.setOnContextClickListenerCompat(eventListener)
|
||||
AdapterDelegateClickListenerAdapter(this, clickListener, MangaGridModel::manga).attach(itemView)
|
||||
sizeResolver.attachToView(lifecycleOwner, itemView, binding.textViewTitle, binding.progressView)
|
||||
|
||||
bind { payloads ->
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
package org.koitharu.kotatsu.list.ui.adapter
|
||||
|
||||
import android.view.View
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import coil.ImageLoader
|
||||
import com.google.android.material.badge.BadgeDrawable
|
||||
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
||||
import org.koitharu.kotatsu.core.ui.image.CoverSizeResolver
|
||||
import org.koitharu.kotatsu.core.ui.image.TrimTransformation
|
||||
import org.koitharu.kotatsu.core.ui.list.AdapterDelegateClickListenerAdapter
|
||||
import org.koitharu.kotatsu.core.util.ext.defaultPlaceholders
|
||||
import org.koitharu.kotatsu.core.util.ext.enqueueWith
|
||||
import org.koitharu.kotatsu.core.util.ext.newImageRequest
|
||||
import org.koitharu.kotatsu.core.util.ext.setOnContextClickListenerCompat
|
||||
import org.koitharu.kotatsu.core.util.ext.source
|
||||
import org.koitharu.kotatsu.core.util.ext.textAndVisible
|
||||
import org.koitharu.kotatsu.databinding.ItemMangaListDetailsBinding
|
||||
@@ -27,14 +26,7 @@ fun mangaListDetailedItemAD(
|
||||
) {
|
||||
var badge: BadgeDrawable? = null
|
||||
|
||||
val listenerAdapter = object : View.OnClickListener, View.OnLongClickListener {
|
||||
override fun onClick(v: View) = clickListener.onItemClick(item.manga, v)
|
||||
|
||||
override fun onLongClick(v: View): Boolean = clickListener.onItemLongClick(item.manga, v)
|
||||
}
|
||||
itemView.setOnClickListener(listenerAdapter)
|
||||
itemView.setOnLongClickListener(listenerAdapter)
|
||||
itemView.setOnContextClickListenerCompat(listenerAdapter)
|
||||
AdapterDelegateClickListenerAdapter(this, clickListener, MangaDetailedListModel::manga).attach(itemView)
|
||||
|
||||
bind { payloads ->
|
||||
binding.textViewTitle.text = item.title
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
package org.koitharu.kotatsu.list.ui.adapter
|
||||
|
||||
import android.view.View
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import coil.ImageLoader
|
||||
import com.google.android.material.badge.BadgeDrawable
|
||||
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
||||
import org.koitharu.kotatsu.core.ui.image.TrimTransformation
|
||||
import org.koitharu.kotatsu.core.ui.list.AdapterDelegateClickListenerAdapter
|
||||
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.core.util.ext.defaultPlaceholders
|
||||
import org.koitharu.kotatsu.core.util.ext.enqueueWith
|
||||
import org.koitharu.kotatsu.core.util.ext.newImageRequest
|
||||
import org.koitharu.kotatsu.core.util.ext.setOnContextClickListenerCompat
|
||||
import org.koitharu.kotatsu.core.util.ext.source
|
||||
import org.koitharu.kotatsu.core.util.ext.textAndVisible
|
||||
import org.koitharu.kotatsu.databinding.ItemMangaListBinding
|
||||
@@ -27,13 +26,7 @@ fun mangaListItemAD(
|
||||
) {
|
||||
var badge: BadgeDrawable? = null
|
||||
|
||||
val eventListener = object : View.OnClickListener, View.OnLongClickListener {
|
||||
override fun onClick(v: View) = clickListener.onItemClick(item.manga, v)
|
||||
override fun onLongClick(v: View): Boolean = clickListener.onItemLongClick(item.manga, v)
|
||||
}
|
||||
itemView.setOnClickListener(eventListener)
|
||||
itemView.setOnLongClickListener(eventListener)
|
||||
itemView.setOnContextClickListenerCompat(eventListener)
|
||||
AdapterDelegateClickListenerAdapter(this, clickListener, MangaCompactListModel::manga).attach(itemView)
|
||||
|
||||
bind {
|
||||
binding.textViewTitle.text = item.title
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.Manifest
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
@@ -88,16 +89,16 @@ class LocalListFragment : MangaListFragment(), FilterCoordinator.Owner {
|
||||
|
||||
override fun onCreateActionMode(
|
||||
controller: ListSelectionController,
|
||||
mode: ActionMode,
|
||||
menuInflater: MenuInflater,
|
||||
menu: Menu,
|
||||
): Boolean {
|
||||
mode.menuInflater.inflate(R.menu.mode_local, menu)
|
||||
return super.onCreateActionMode(controller, mode, menu)
|
||||
menuInflater.inflate(R.menu.mode_local, menu)
|
||||
return super.onCreateActionMode(controller, menuInflater, menu)
|
||||
}
|
||||
|
||||
override fun onActionItemClicked(
|
||||
controller: ListSelectionController,
|
||||
mode: ActionMode,
|
||||
mode: ActionMode?,
|
||||
item: MenuItem,
|
||||
): Boolean {
|
||||
return when (item.itemId) {
|
||||
@@ -109,7 +110,7 @@ class LocalListFragment : MangaListFragment(), FilterCoordinator.Owner {
|
||||
R.id.action_share -> {
|
||||
val files = selectedItems.map { it.url.toUri().toFile() }
|
||||
ShareHelper(requireContext()).shareCbz(files)
|
||||
mode.finish()
|
||||
mode?.finish()
|
||||
true
|
||||
}
|
||||
|
||||
@@ -117,13 +118,13 @@ class LocalListFragment : MangaListFragment(), FilterCoordinator.Owner {
|
||||
}
|
||||
}
|
||||
|
||||
private fun showDeletionConfirm(ids: Set<Long>, mode: ActionMode) {
|
||||
private fun showDeletionConfirm(ids: Set<Long>, mode: ActionMode?) {
|
||||
MaterialAlertDialogBuilder(context ?: return)
|
||||
.setTitle(R.string.delete_manga)
|
||||
.setMessage(getString(R.string.text_delete_local_manga_batch))
|
||||
.setPositiveButton(R.string.delete) { _, _ ->
|
||||
viewModel.delete(ids)
|
||||
mode.finish()
|
||||
mode?.finish()
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show()
|
||||
|
||||
@@ -5,7 +5,6 @@ import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.core.view.MenuProvider
|
||||
import androidx.fragment.app.viewModels
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
@@ -56,9 +55,13 @@ class RemoteListFragment : MangaListFragment(), FilterCoordinator.Owner {
|
||||
viewModel.loadNextPage()
|
||||
}
|
||||
|
||||
override fun onCreateActionMode(controller: ListSelectionController, mode: ActionMode, menu: Menu): Boolean {
|
||||
mode.menuInflater.inflate(R.menu.mode_remote, menu)
|
||||
return super.onCreateActionMode(controller, mode, menu)
|
||||
override fun onCreateActionMode(
|
||||
controller: ListSelectionController,
|
||||
menuInflater: MenuInflater,
|
||||
menu: Menu
|
||||
): Boolean {
|
||||
menuInflater.inflate(R.menu.mode_remote, menu)
|
||||
return super.onCreateActionMode(controller, menuInflater, menu)
|
||||
}
|
||||
|
||||
override fun onFilterClick(view: View?) {
|
||||
|
||||
@@ -20,8 +20,7 @@ fun scrobblingMangaAD(
|
||||
{ layoutInflater, parent -> ItemScrobblingMangaBinding.inflate(layoutInflater, parent, false) },
|
||||
) {
|
||||
|
||||
val clickListenerAdapter = AdapterDelegateClickListenerAdapter(this, clickListener)
|
||||
itemView.setOnClickListener(clickListenerAdapter)
|
||||
AdapterDelegateClickListenerAdapter(this, clickListener).attach(itemView)
|
||||
|
||||
bind {
|
||||
binding.imageViewCover.newImageRequest(lifecycleOwner, item.coverUrl)?.run {
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.activity.viewModels
|
||||
@@ -118,7 +119,11 @@ class SearchActivity :
|
||||
}
|
||||
|
||||
override fun onItemLongClick(item: Manga, view: View): Boolean {
|
||||
return selectionController.onItemLongClick(item.id)
|
||||
return selectionController.onItemLongClick(view, item.id)
|
||||
}
|
||||
|
||||
override fun onItemContextClick(item: Manga, view: View): Boolean {
|
||||
return selectionController.onItemContextClick(view, item.id)
|
||||
}
|
||||
|
||||
override fun onReadClick(manga: Manga, view: View) {
|
||||
@@ -155,28 +160,32 @@ class SearchActivity :
|
||||
viewBinding.recyclerView.invalidateNestedItemDecorations()
|
||||
}
|
||||
|
||||
override fun onCreateActionMode(controller: ListSelectionController, mode: ActionMode, menu: Menu): Boolean {
|
||||
mode.menuInflater.inflate(R.menu.mode_remote, menu)
|
||||
override fun onCreateActionMode(
|
||||
controller: ListSelectionController,
|
||||
menuInflater: MenuInflater,
|
||||
menu: Menu
|
||||
): Boolean {
|
||||
menuInflater.inflate(R.menu.mode_remote, menu)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onActionItemClicked(controller: ListSelectionController, mode: ActionMode, item: MenuItem): Boolean {
|
||||
override fun onActionItemClicked(controller: ListSelectionController, mode: ActionMode?, item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.action_share -> {
|
||||
ShareHelper(this).shareMangaLinks(collectSelectedItems())
|
||||
mode.finish()
|
||||
mode?.finish()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.action_favourite -> {
|
||||
FavoriteSheet.show(supportFragmentManager, collectSelectedItems())
|
||||
mode.finish()
|
||||
mode?.finish()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.action_save -> {
|
||||
viewModel.download(collectSelectedItems())
|
||||
mode.finish()
|
||||
mode?.finish()
|
||||
true
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.core.view.MenuProvider
|
||||
import androidx.fragment.app.viewModels
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
@@ -29,11 +28,11 @@ class SuggestionsFragment : MangaListFragment() {
|
||||
|
||||
override fun onCreateActionMode(
|
||||
controller: ListSelectionController,
|
||||
mode: ActionMode,
|
||||
menuInflater: MenuInflater,
|
||||
menu: Menu,
|
||||
): Boolean {
|
||||
mode.menuInflater.inflate(R.menu.mode_remote, menu)
|
||||
return super.onCreateActionMode(controller, mode, menu)
|
||||
menuInflater.inflate(R.menu.mode_remote, menu)
|
||||
return super.onCreateActionMode(controller, menuInflater, menu)
|
||||
}
|
||||
|
||||
private inner class SuggestionMenuProvider : MenuProvider {
|
||||
@@ -71,10 +70,11 @@ class SuggestionsFragment : MangaListFragment() {
|
||||
companion object {
|
||||
|
||||
@Deprecated(
|
||||
"", ReplaceWith(
|
||||
"",
|
||||
ReplaceWith(
|
||||
"SuggestionsFragment()",
|
||||
"org.koitharu.kotatsu.suggestions.ui.SuggestionsFragment"
|
||||
)
|
||||
"org.koitharu.kotatsu.suggestions.ui.SuggestionsFragment",
|
||||
),
|
||||
)
|
||||
fun newInstance() = SuggestionsFragment()
|
||||
}
|
||||
|
||||
@@ -62,6 +62,8 @@ class FeedFragment :
|
||||
onItemClick(item.manga, v)
|
||||
}
|
||||
with(binding.recyclerView) {
|
||||
val paddingVertical = resources.getDimensionPixelSize(R.dimen.list_spacing_normal)
|
||||
setPadding(0, paddingVertical, 0, paddingVertical)
|
||||
layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
|
||||
adapter = feedAdapter
|
||||
setHasFixedSize(true)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.koitharu.kotatsu.tracker.ui.updates
|
||||
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.fragment.app.viewModels
|
||||
@@ -17,16 +18,20 @@ class UpdatesFragment : MangaListFragment() {
|
||||
|
||||
override fun onScrolledToEnd() = Unit
|
||||
|
||||
override fun onCreateActionMode(controller: ListSelectionController, mode: ActionMode, menu: Menu): Boolean {
|
||||
mode.menuInflater.inflate(R.menu.mode_updates, menu)
|
||||
return super.onCreateActionMode(controller, mode, menu)
|
||||
override fun onCreateActionMode(
|
||||
controller: ListSelectionController,
|
||||
menuInflater: MenuInflater,
|
||||
menu: Menu
|
||||
): Boolean {
|
||||
menuInflater.inflate(R.menu.mode_updates, menu)
|
||||
return super.onCreateActionMode(controller, menuInflater, menu)
|
||||
}
|
||||
|
||||
override fun onActionItemClicked(controller: ListSelectionController, mode: ActionMode, item: MenuItem): Boolean {
|
||||
override fun onActionItemClicked(controller: ListSelectionController, mode: ActionMode?, item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.action_remove -> {
|
||||
viewModel.remove(controller.snapshot())
|
||||
mode.finish()
|
||||
mode?.finish()
|
||||
true
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user