Bottom action menu in library

This commit is contained in:
arkon 2020-03-08 15:50:07 -04:00
parent 316211372c
commit af2ef36d68
4 changed files with 46 additions and 35 deletions

View file

@ -32,6 +32,7 @@ import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.library.LibraryUpdateService import eu.kanade.tachiyomi.data.library.LibraryUpdateService
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.ui.base.controller.BottomActionMenuController
import eu.kanade.tachiyomi.ui.base.controller.NucleusController import eu.kanade.tachiyomi.ui.base.controller.NucleusController
import eu.kanade.tachiyomi.ui.base.controller.RootController import eu.kanade.tachiyomi.ui.base.controller.RootController
import eu.kanade.tachiyomi.ui.base.controller.SecondaryDrawerController import eu.kanade.tachiyomi.ui.base.controller.SecondaryDrawerController
@ -41,6 +42,7 @@ import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.manga.MangaController import eu.kanade.tachiyomi.ui.manga.MangaController
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.util.view.inflate import eu.kanade.tachiyomi.util.view.inflate
import eu.kanade.tachiyomi.widget.BottomActionMenu
import java.io.IOException import java.io.IOException
import kotlinx.android.synthetic.main.library_controller.empty_view import kotlinx.android.synthetic.main.library_controller.empty_view
import kotlinx.android.synthetic.main.library_controller.library_pager import kotlinx.android.synthetic.main.library_controller.library_pager
@ -58,6 +60,7 @@ class LibraryController(
RootController, RootController,
TabbedController, TabbedController,
SecondaryDrawerController, SecondaryDrawerController,
BottomActionMenuController,
ActionMode.Callback, ActionMode.Callback,
ChangeMangaCategoriesDialog.Listener, ChangeMangaCategoriesDialog.Listener,
DeleteLibraryMangasDialog.Listener { DeleteLibraryMangasDialog.Listener {
@ -72,6 +75,7 @@ class LibraryController(
* Action mode for selections. * Action mode for selections.
*/ */
private var actionMode: ActionMode? = null private var actionMode: ActionMode? = null
private var bottomActionMenu: BottomActionMenu? = null
/** /**
* Library search query. * Library search query.
@ -179,9 +183,9 @@ class LibraryController(
} }
override fun onDestroyView(view: View) { override fun onDestroyView(view: View) {
destroyActionModeIfNeeded()
adapter?.onDestroy() adapter?.onDestroy()
adapter = null adapter = null
actionMode = null
tabsVisibilitySubscription?.unsubscribe() tabsVisibilitySubscription?.unsubscribe()
tabsVisibilitySubscription = null tabsVisibilitySubscription = null
super.onDestroyView(view) super.onDestroyView(view)
@ -320,7 +324,7 @@ class LibraryController(
/** /**
* Destroys the action mode. * Destroys the action mode.
*/ */
fun destroyActionModeIfNeeded() { private fun destroyActionModeIfNeeded() {
actionMode?.finish() actionMode?.finish()
} }
@ -414,7 +418,7 @@ class LibraryController(
} }
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean { override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
mode.menuInflater.inflate(R.menu.library_selection, menu) mode.menuInflater.inflate(R.menu.generic_selection, menu)
return true return true
} }
@ -425,7 +429,9 @@ class LibraryController(
destroyActionModeIfNeeded() destroyActionModeIfNeeded()
} else { } else {
mode.title = count.toString() mode.title = count.toString()
menu.findItem(R.id.action_edit_cover)?.isVisible = count == 1
bottomActionMenu?.show(mode.menuInflater)
bottomActionMenu?.findItem(R.id.action_edit_cover)?.isVisible = count == 1
} }
return false return false
} }
@ -445,12 +451,20 @@ class LibraryController(
} }
override fun onDestroyActionMode(mode: ActionMode?) { override fun onDestroyActionMode(mode: ActionMode?) {
bottomActionMenu?.hide()
// Clear all the manga selections and notify child views. // Clear all the manga selections and notify child views.
selectedMangas.clear() selectedMangas.clear()
selectionRelay.call(LibrarySelectionEvent.Cleared()) selectionRelay.call(LibrarySelectionEvent.Cleared())
actionMode = null actionMode = null
} }
override fun configureBottomActionMenu(bottomActionMenu: BottomActionMenu) {
this.bottomActionMenu = bottomActionMenu
bottomActionMenu.configure(
R.menu.library_selection
) { onActionItemClicked(actionMode!!, it!!) }
}
fun openManga(manga: Manga) { fun openManga(manga: Manga) {
// Notify the presenter a manga is being opened. // Notify the presenter a manga is being opened.
presenter.onOpenManga() presenter.onOpenManga()

View file

@ -107,8 +107,8 @@ class UpdatesController : NucleusController<UpdatesPresenter>(),
} }
override fun onDestroyView(view: View) { override fun onDestroyView(view: View) {
destroyActionModeIfNeeded()
adapter = null adapter = null
actionMode = null
super.onDestroyView(view) super.onDestroyView(view)
} }
@ -116,7 +116,7 @@ class UpdatesController : NucleusController<UpdatesPresenter>(),
* Returns selected chapters * Returns selected chapters
* @return list of selected chapters * @return list of selected chapters
*/ */
fun getSelectedChapters(): List<UpdatesItem> { private fun getSelectedChapters(): List<UpdatesItem> {
val adapter = adapter ?: return emptyList() val adapter = adapter ?: return emptyList()
return adapter.selectedPositions.mapNotNull { adapter.getItem(it) as? UpdatesItem } return adapter.selectedPositions.mapNotNull { adapter.getItem(it) as? UpdatesItem }
} }
@ -175,7 +175,7 @@ class UpdatesController : NucleusController<UpdatesPresenter>(),
* Download selected items * Download selected items
* @param chapters list of selected [UpdatesItem]s * @param chapters list of selected [UpdatesItem]s
*/ */
fun downloadChapters(chapters: List<UpdatesItem>) { private fun downloadChapters(chapters: List<UpdatesItem>) {
presenter.downloadChapters(chapters) presenter.downloadChapters(chapters)
} }
@ -216,13 +216,21 @@ class UpdatesController : NucleusController<UpdatesPresenter>(),
* Mark chapter as read * Mark chapter as read
* @param chapters list of chapters * @param chapters list of chapters
*/ */
fun markAsRead(chapters: List<UpdatesItem>) { private fun markAsRead(chapters: List<UpdatesItem>) {
presenter.markChapterRead(chapters, true) presenter.markChapterRead(chapters, true)
if (presenter.preferences.removeAfterMarkedAsRead()) { if (presenter.preferences.removeAfterMarkedAsRead()) {
deleteChapters(chapters) deleteChapters(chapters)
} }
} }
/**
* Mark chapter as unread
* @param chapters list of selected [UpdatesItem]
*/
private fun markAsUnread(chapters: List<UpdatesItem>) {
presenter.markChapterRead(chapters, false)
}
override fun deleteChapters(chaptersToDelete: List<UpdatesItem>) { override fun deleteChapters(chaptersToDelete: List<UpdatesItem>) {
DeletingChaptersDialog().showDialog(router) DeletingChaptersDialog().showDialog(router)
presenter.deleteChapters(chaptersToDelete) presenter.deleteChapters(chaptersToDelete)
@ -235,20 +243,12 @@ class UpdatesController : NucleusController<UpdatesPresenter>(),
actionMode?.finish() actionMode?.finish()
} }
/**
* Mark chapter as unread
* @param chapters list of selected [UpdatesItem]
*/
fun markAsUnread(chapters: List<UpdatesItem>) {
presenter.markChapterRead(chapters, false)
}
override fun onCoverClick(position: Int) { override fun onCoverClick(position: Int) {
val chapterClicked = adapter?.getItem(position) as? UpdatesItem ?: return val chapterClicked = adapter?.getItem(position) as? UpdatesItem ?: return
openManga(chapterClicked) openManga(chapterClicked)
} }
fun openManga(chapter: UpdatesItem) { private fun openManga(chapter: UpdatesItem) {
router.pushController(MangaController(chapter.manga).withFadeTransaction()) router.pushController(MangaController(chapter.manga).withFadeTransaction())
} }
@ -272,7 +272,7 @@ class UpdatesController : NucleusController<UpdatesPresenter>(),
/** /**
* Called to dismiss deleting dialog * Called to dismiss deleting dialog
*/ */
fun dismissDeletingDialog() { private fun dismissDeletingDialog() {
router.popControllerWithTag(DeletingChaptersDialog.TAG) router.popControllerWithTag(DeletingChaptersDialog.TAG)
} }
@ -284,7 +284,6 @@ class UpdatesController : NucleusController<UpdatesPresenter>(),
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean { override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
mode.menuInflater.inflate(R.menu.generic_selection, menu) mode.menuInflater.inflate(R.menu.generic_selection, menu)
adapter?.mode = SelectableAdapter.Mode.MULTI adapter?.mode = SelectableAdapter.Mode.MULTI
return true return true
} }
@ -331,16 +330,16 @@ class UpdatesController : NucleusController<UpdatesPresenter>(),
actionMode = null actionMode = null
} }
private fun selectAll() {
val adapter = adapter ?: return
adapter.selectAll()
actionMode?.invalidate()
}
override fun configureBottomActionMenu(bottomActionMenu: BottomActionMenu) { override fun configureBottomActionMenu(bottomActionMenu: BottomActionMenu) {
this.bottomActionMenu = bottomActionMenu this.bottomActionMenu = bottomActionMenu
bottomActionMenu.configure( bottomActionMenu.configure(
R.menu.updates_chapter_selection R.menu.updates_chapter_selection
) { onActionItemClicked(actionMode!!, it!!) } ) { onActionItemClicked(actionMode!!, it!!) }
} }
private fun selectAll() {
val adapter = adapter ?: return
adapter.selectAll()
actionMode?.invalidate()
}
} }

View file

@ -6,6 +6,7 @@ import android.view.MenuInflater
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.widget.FrameLayout import android.widget.FrameLayout
import androidx.annotation.IdRes
import androidx.annotation.MenuRes import androidx.annotation.MenuRes
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import kotlinx.android.synthetic.main.common_bottom_action_menu.view.bottom_menu import kotlinx.android.synthetic.main.common_bottom_action_menu.view.bottom_menu
@ -31,6 +32,10 @@ class BottomActionMenu @JvmOverloads constructor(context: Context, attrs: Attrib
bottom_menu.setOnMenuItemClickListener(null) bottom_menu.setOnMenuItemClickListener(null)
} }
fun findItem(@IdRes itemId: Int): MenuItem? {
return bottom_menu.menu.findItem(itemId)
}
fun show(menuInflater: MenuInflater) { fun show(menuInflater: MenuInflater) {
// Avoid re-inflating the menu // Avoid re-inflating the menu
if (bottom_menu.menu.size() == 0) { if (bottom_menu.menu.size() == 0) {

View file

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" <menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
@ -7,24 +6,18 @@
android:id="@+id/action_edit_cover" android:id="@+id/action_edit_cover"
android:icon="@drawable/ic_create_white_24dp" android:icon="@drawable/ic_create_white_24dp"
android:title="@string/action_edit_cover" android:title="@string/action_edit_cover"
app:showAsAction="ifRoom" /> app:showAsAction="always" />
<item <item
android:id="@+id/action_move_to_category" android:id="@+id/action_move_to_category"
android:icon="@drawable/ic_label_white_24dp" android:icon="@drawable/ic_label_white_24dp"
android:title="@string/action_move_category" android:title="@string/action_move_category"
app:showAsAction="ifRoom" /> app:showAsAction="always" />
<item <item
android:id="@+id/action_delete" android:id="@+id/action_delete"
android:icon="@drawable/ic_delete_white_24dp" android:icon="@drawable/ic_delete_white_24dp"
android:title="@string/action_delete" android:title="@string/action_delete"
app:showAsAction="ifRoom" /> app:showAsAction="always" />
<item
android:id="@+id/action_select_all"
android:icon="@drawable/ic_select_all_white_24dp"
android:title="@string/action_select_all"
app:showAsAction="ifRoom" />
</menu> </menu>