Browse Source

Use bottom sheet for library settings

arkon 5 years ago
parent
commit
488f81ef74

+ 19 - 39
app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt

@@ -15,8 +15,6 @@ import androidx.appcompat.app.AppCompatActivity
 import androidx.appcompat.view.ActionMode
 import androidx.appcompat.widget.SearchView
 import androidx.core.graphics.drawable.DrawableCompat
-import androidx.core.view.GravityCompat
-import androidx.drawerlayout.widget.DrawerLayout
 import com.bluelinelabs.conductor.ControllerChangeHandler
 import com.bluelinelabs.conductor.ControllerChangeType
 import com.f2prateek.rx.preferences.Preference
@@ -33,19 +31,16 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 import eu.kanade.tachiyomi.data.preference.getOrDefault
 import eu.kanade.tachiyomi.ui.base.controller.NucleusController
 import eu.kanade.tachiyomi.ui.base.controller.RootController
-import eu.kanade.tachiyomi.ui.base.controller.SecondaryDrawerController
 import eu.kanade.tachiyomi.ui.base.controller.TabbedController
 import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
 import eu.kanade.tachiyomi.ui.main.MainActivity
 import eu.kanade.tachiyomi.ui.manga.MangaController
 import eu.kanade.tachiyomi.util.system.getResourceColor
 import eu.kanade.tachiyomi.util.system.toast
-import eu.kanade.tachiyomi.util.view.inflate
 import java.io.IOException
 import kotlinx.android.synthetic.main.library_controller.action_toolbar
 import kotlinx.android.synthetic.main.library_controller.empty_view
 import kotlinx.android.synthetic.main.library_controller.library_pager
-import kotlinx.android.synthetic.main.main_activity.drawer
 import kotlinx.android.synthetic.main.main_activity.tabs
 import rx.Subscription
 import timber.log.Timber
@@ -58,7 +53,6 @@ class LibraryController(
 ) : NucleusController<LibraryPresenter>(bundle),
         RootController,
         TabbedController,
-        SecondaryDrawerController,
         ActionMode.Callback,
         ChangeMangaCategoriesDialog.Listener,
         DeleteLibraryMangasDialog.Listener {
@@ -118,14 +112,9 @@ class LibraryController(
     private var adapter: LibraryAdapter? = null
 
     /**
-     * Navigation view containing filter/sort/display items.
+     * Sheet containing filter/sort/display items.
      */
-    private var navView: LibraryNavigationView? = null
-
-    /**
-     * Drawer listener to allow swipe only for closing the drawer.
-     */
-    private var drawerListener: DrawerLayout.DrawerListener? = null
+    private var settingsSheet: LibrarySettingsSheet? = null
 
     private var tabsVisibilityRelay: BehaviorRelay<Boolean> = BehaviorRelay.create(false)
 
@@ -169,6 +158,15 @@ class LibraryController(
         if (selectedMangas.isNotEmpty()) {
             createActionModeIfNeeded()
         }
+
+        settingsSheet = LibrarySettingsSheet(activity!!) { group ->
+            when (group) {
+                is LibrarySettingsSheet.Settings.FilterGroup -> onFilterChanged()
+                is LibrarySettingsSheet.Settings.SortGroup -> onSortChanged()
+                is LibrarySettingsSheet.Settings.DisplayGroup -> reattachAdapter()
+                is LibrarySettingsSheet.Settings.BadgeGroup -> onDownloadBadgeChanged()
+            }
+        }
     }
 
     override fun onChangeStarted(handler: ControllerChangeHandler, type: ControllerChangeType) {
@@ -184,32 +182,12 @@ class LibraryController(
         action_toolbar.destroy()
         adapter?.onDestroy()
         adapter = null
+        settingsSheet = null
         tabsVisibilitySubscription?.unsubscribe()
         tabsVisibilitySubscription = null
         super.onDestroyView(view)
     }
 
-    override fun createSecondaryDrawer(drawer: DrawerLayout): ViewGroup {
-        val view = drawer.inflate(R.layout.library_drawer) as LibraryNavigationView
-        navView = view
-        drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, GravityCompat.END)
-
-        navView?.onGroupClicked = { group ->
-            when (group) {
-                is LibraryNavigationView.FilterGroup -> onFilterChanged()
-                is LibraryNavigationView.SortGroup -> onSortChanged()
-                is LibraryNavigationView.DisplayGroup -> reattachAdapter()
-                is LibraryNavigationView.BadgeGroup -> onDownloadBadgeChanged()
-            }
-        }
-
-        return view
-    }
-
-    override fun cleanupSecondaryDrawer(drawer: DrawerLayout) {
-        navView = null
-    }
-
     override fun configureTabs(tabs: TabLayout) {
         with(tabs) {
             tabGravity = TabLayout.GRAVITY_CENTER
@@ -231,6 +209,10 @@ class LibraryController(
         tabsVisibilitySubscription = null
     }
 
+    fun showSettingsSheet() {
+        settingsSheet?.show()
+    }
+
     fun onNextLibraryUpdate(categories: List<Category>, mangaMap: Map<Int, List<LibraryItem>>) {
         val view = view ?: return
         val adapter = adapter ?: return
@@ -364,12 +346,12 @@ class LibraryController(
     }
 
     override fun onPrepareOptionsMenu(menu: Menu) {
-        val navView = navView ?: return
+        val settingsSheet = settingsSheet ?: return
 
         val filterItem = menu.findItem(R.id.action_filter)
 
         // Tint icon if there's a filter active
-        if (navView.hasActiveFilters()) {
+        if (settingsSheet.hasActiveFilters()) {
             val filterColor = activity!!.getResourceColor(R.attr.colorFilterActive)
             DrawableCompat.setTint(filterItem.icon, filterColor)
         }
@@ -378,9 +360,7 @@ class LibraryController(
     override fun onOptionsItemSelected(item: MenuItem): Boolean {
         when (item.itemId) {
             R.id.action_search -> expandActionViewFromInteraction = true
-            R.id.action_filter -> {
-                navView?.let { activity?.drawer?.openDrawer(GravityCompat.END) }
-            }
+            R.id.action_filter -> showSettingsSheet()
             R.id.action_update_library -> {
                 activity?.let { LibraryUpdateService.start(it) }
             }

+ 0 - 216
app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryNavigationView.kt

@@ -1,216 +0,0 @@
-package eu.kanade.tachiyomi.ui.library
-
-import android.content.Context
-import android.util.AttributeSet
-import eu.kanade.tachiyomi.R
-import eu.kanade.tachiyomi.data.preference.PreferencesHelper
-import eu.kanade.tachiyomi.data.preference.getOrDefault
-import eu.kanade.tachiyomi.widget.ExtendedNavigationView
-import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.MultiSort.Companion.SORT_ASC
-import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.MultiSort.Companion.SORT_DESC
-import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.MultiSort.Companion.SORT_NONE
-import uy.kohesive.injekt.injectLazy
-
-/**
- * The navigation view shown in a drawer with the different options to show the library.
- */
-class LibraryNavigationView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
-    ExtendedNavigationView(context, attrs) {
-
-    /**
-     * Preferences helper.
-     */
-    private val preferences: PreferencesHelper by injectLazy()
-
-    /**
-     * List of groups shown in the view.
-     */
-    private val groups = listOf(FilterGroup(), SortGroup(), DisplayGroup(), BadgeGroup())
-
-    /**
-     * Adapter instance.
-     */
-    private val adapter = Adapter(groups.map { it.createItems() }.flatten())
-
-    /**
-     * Click listener to notify the parent fragment when an item from a group is clicked.
-     */
-    var onGroupClicked: (Group) -> Unit = {}
-
-    init {
-        recycler.adapter = adapter
-        addView(recycler)
-
-        groups.forEach { it.initModels() }
-    }
-
-    /**
-     * Returns true if there's at least one filter from [FilterGroup] active.
-     */
-    fun hasActiveFilters(): Boolean {
-        return (groups[0] as FilterGroup).items.any { it.checked }
-    }
-
-    /**
-     * Adapter of the recycler view.
-     */
-    inner class Adapter(items: List<Item>) : ExtendedNavigationView.Adapter(items) {
-
-        override fun onItemClicked(item: Item) {
-            if (item is GroupedItem) {
-                item.group.onItemClicked(item)
-                onGroupClicked(item.group)
-            }
-        }
-    }
-
-    /**
-     * Filters group (unread, downloaded, ...).
-     */
-    inner class FilterGroup : Group {
-
-        private val downloaded = Item.CheckboxGroup(R.string.action_filter_downloaded, this)
-
-        private val unread = Item.CheckboxGroup(R.string.action_filter_unread, this)
-
-        private val completed = Item.CheckboxGroup(R.string.completed, this)
-
-        override val items = listOf(downloaded, unread, completed)
-
-        override val header = Item.Header(R.string.action_filter)
-
-        override val footer = Item.Separator()
-
-        override fun initModels() {
-            downloaded.checked = preferences.filterDownloaded().getOrDefault()
-            unread.checked = preferences.filterUnread().getOrDefault()
-            completed.checked = preferences.filterCompleted().getOrDefault()
-        }
-
-        override fun onItemClicked(item: Item) {
-            item as Item.CheckboxGroup
-            item.checked = !item.checked
-            when (item) {
-                downloaded -> preferences.filterDownloaded().set(item.checked)
-                unread -> preferences.filterUnread().set(item.checked)
-                completed -> preferences.filterCompleted().set(item.checked)
-            }
-
-            adapter.notifyItemChanged(item)
-        }
-    }
-
-    /**
-     * Sorting group (alphabetically, by last read, ...) and ascending or descending.
-     */
-    inner class SortGroup : Group {
-
-        private val alphabetically = Item.MultiSort(R.string.action_sort_alpha, this)
-
-        private val total = Item.MultiSort(R.string.action_sort_total, this)
-
-        private val lastRead = Item.MultiSort(R.string.action_sort_last_read, this)
-
-        private val lastChecked = Item.MultiSort(R.string.action_sort_last_checked, this)
-
-        private val unread = Item.MultiSort(R.string.action_filter_unread, this)
-
-        private val latestChapter = Item.MultiSort(R.string.action_sort_latest_chapter, this)
-
-        override val items = listOf(alphabetically, lastRead, lastChecked, unread, total, latestChapter)
-
-        override val header = Item.Header(R.string.action_sort)
-
-        override val footer = Item.Separator()
-
-        override fun initModels() {
-            val sorting = preferences.librarySortingMode().getOrDefault()
-            val order = if (preferences.librarySortingAscending().getOrDefault())
-                SORT_ASC else SORT_DESC
-
-            alphabetically.state = if (sorting == LibrarySort.ALPHA) order else SORT_NONE
-            lastRead.state = if (sorting == LibrarySort.LAST_READ) order else SORT_NONE
-            lastChecked.state = if (sorting == LibrarySort.LAST_CHECKED) order else SORT_NONE
-            unread.state = if (sorting == LibrarySort.UNREAD) order else SORT_NONE
-            total.state = if (sorting == LibrarySort.TOTAL) order else SORT_NONE
-            latestChapter.state = if (sorting == LibrarySort.LATEST_CHAPTER) order else SORT_NONE
-        }
-
-        override fun onItemClicked(item: Item) {
-            item as Item.MultiStateGroup
-            val prevState = item.state
-
-            item.group.items.forEach { (it as Item.MultiStateGroup).state = SORT_NONE }
-            item.state = when (prevState) {
-                SORT_NONE -> SORT_ASC
-                SORT_ASC -> SORT_DESC
-                SORT_DESC -> SORT_ASC
-                else -> throw Exception("Unknown state")
-            }
-
-            preferences.librarySortingMode().set(when (item) {
-                alphabetically -> LibrarySort.ALPHA
-                lastRead -> LibrarySort.LAST_READ
-                lastChecked -> LibrarySort.LAST_CHECKED
-                unread -> LibrarySort.UNREAD
-                total -> LibrarySort.TOTAL
-                latestChapter -> LibrarySort.LATEST_CHAPTER
-                else -> throw Exception("Unknown sorting")
-            })
-            preferences.librarySortingAscending().set(item.state == SORT_ASC)
-
-            item.group.items.forEach { adapter.notifyItemChanged(it) }
-        }
-    }
-
-    inner class BadgeGroup : Group {
-        private val downloadBadge = Item.CheckboxGroup(R.string.action_display_download_badge, this)
-        override val header = null
-        override val footer = null
-        override val items = listOf(downloadBadge)
-        override fun initModels() {
-            downloadBadge.checked = preferences.downloadBadge().getOrDefault()
-        }
-
-        override fun onItemClicked(item: Item) {
-            item as Item.CheckboxGroup
-            item.checked = !item.checked
-            preferences.downloadBadge().set((item.checked))
-            adapter.notifyItemChanged(item)
-        }
-    }
-
-    /**
-     * Display group, to show the library as a list or a grid.
-     */
-    inner class DisplayGroup : Group {
-
-        private val grid = Item.Radio(R.string.action_display_grid, this)
-
-        private val list = Item.Radio(R.string.action_display_list, this)
-
-        override val items = listOf(grid, list)
-
-        override val header = Item.Header(R.string.action_display)
-
-        override val footer = null
-
-        override fun initModels() {
-            val asList = preferences.libraryAsList().getOrDefault()
-            grid.checked = !asList
-            list.checked = asList
-        }
-
-        override fun onItemClicked(item: Item) {
-            item as Item.Radio
-            if (item.checked) return
-
-            item.group.items.forEach { (it as Item.Radio).checked = false }
-            item.checked = true
-
-            preferences.libraryAsList().set(item == list)
-
-            item.group.items.forEach { adapter.notifyItemChanged(it) }
-        }
-    }
-}

+ 243 - 0
app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt

@@ -0,0 +1,243 @@
+package eu.kanade.tachiyomi.ui.library
+
+import android.app.Activity
+import android.content.Context
+import android.util.AttributeSet
+import com.google.android.material.bottomsheet.BottomSheetDialog
+import eu.kanade.tachiyomi.R
+import eu.kanade.tachiyomi.data.preference.PreferencesHelper
+import eu.kanade.tachiyomi.data.preference.getOrDefault
+import eu.kanade.tachiyomi.widget.ExtendedNavigationView
+import uy.kohesive.injekt.injectLazy
+
+class LibrarySettingsSheet(
+    activity: Activity,
+    onGroupClickListener: (ExtendedNavigationView.Group) -> Unit
+) : BottomSheetDialog(activity) {
+
+    private var navView: Settings
+
+    init {
+        navView = Settings(activity)
+        navView.onGroupClicked = onGroupClickListener
+
+        setContentView(navView)
+    }
+
+    fun hasActiveFilters(): Boolean {
+        return navView.hasActiveFilters()
+    }
+
+    /**
+     * The navigation view shown in the sheet with the different options to show the library.
+     */
+    class Settings @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
+        ExtendedNavigationView(context, attrs) {
+
+        private val preferences: PreferencesHelper by injectLazy()
+
+        /**
+         * List of groups shown in the view.
+         */
+        private val groups = listOf(FilterGroup(), SortGroup(), DisplayGroup(), BadgeGroup())
+
+        /**
+         * Adapter instance.
+         */
+        private val adapter = Adapter(groups.map { it.createItems() }.flatten())
+
+        /**
+         * Click listener to notify the parent fragment when an item from a group is clicked.
+         */
+        var onGroupClicked: (Group) -> Unit = {}
+
+        init {
+            recycler.adapter = adapter
+            addView(recycler)
+
+            groups.forEach { it.initModels() }
+        }
+
+        /**
+         * Returns true if there's at least one filter from [FilterGroup] active.
+         */
+        fun hasActiveFilters(): Boolean {
+            return (groups[0] as FilterGroup).items.any { it.checked }
+        }
+
+        /**
+         * Adapter of the recycler view.
+         */
+        inner class Adapter(items: List<Item>) : ExtendedNavigationView.Adapter(items) {
+
+            override fun onItemClicked(item: Item) {
+                if (item is GroupedItem) {
+                    item.group.onItemClicked(item)
+                    onGroupClicked(item.group)
+                }
+            }
+        }
+
+        /**
+         * Filters group (unread, downloaded, ...).
+         */
+        inner class FilterGroup : Group {
+
+            private val downloaded = Item.CheckboxGroup(R.string.action_filter_downloaded, this)
+
+            private val unread = Item.CheckboxGroup(R.string.action_filter_unread, this)
+
+            private val completed = Item.CheckboxGroup(R.string.completed, this)
+
+            override val items = listOf(downloaded, unread, completed)
+
+            override val header = Item.Header(R.string.action_filter)
+
+            override val footer = Item.Separator()
+
+            override fun initModels() {
+                downloaded.checked = preferences.filterDownloaded().getOrDefault()
+                unread.checked = preferences.filterUnread().getOrDefault()
+                completed.checked = preferences.filterCompleted().getOrDefault()
+            }
+
+            override fun onItemClicked(item: Item) {
+                item as Item.CheckboxGroup
+                item.checked = !item.checked
+                when (item) {
+                    downloaded -> preferences.filterDownloaded().set(item.checked)
+                    unread -> preferences.filterUnread().set(item.checked)
+                    completed -> preferences.filterCompleted().set(item.checked)
+                }
+
+                adapter.notifyItemChanged(item)
+            }
+        }
+
+        /**
+         * Sorting group (alphabetically, by last read, ...) and ascending or descending.
+         */
+        inner class SortGroup : Group {
+
+            private val alphabetically = Item.MultiSort(R.string.action_sort_alpha, this)
+
+            private val total = Item.MultiSort(R.string.action_sort_total, this)
+
+            private val lastRead = Item.MultiSort(R.string.action_sort_last_read, this)
+
+            private val lastChecked = Item.MultiSort(R.string.action_sort_last_checked, this)
+
+            private val unread = Item.MultiSort(R.string.action_filter_unread, this)
+
+            private val latestChapter = Item.MultiSort(R.string.action_sort_latest_chapter, this)
+
+            override val items =
+                listOf(alphabetically, lastRead, lastChecked, unread, total, latestChapter)
+
+            override val header = Item.Header(R.string.action_sort)
+
+            override val footer = Item.Separator()
+
+            override fun initModels() {
+                val sorting = preferences.librarySortingMode().getOrDefault()
+                val order = if (preferences.librarySortingAscending().getOrDefault())
+                    Item.MultiSort.SORT_ASC else Item.MultiSort.SORT_DESC
+
+                alphabetically.state =
+                    if (sorting == LibrarySort.ALPHA) order else Item.MultiSort.SORT_NONE
+                lastRead.state =
+                    if (sorting == LibrarySort.LAST_READ) order else Item.MultiSort.SORT_NONE
+                lastChecked.state =
+                    if (sorting == LibrarySort.LAST_CHECKED) order else Item.MultiSort.SORT_NONE
+                unread.state =
+                    if (sorting == LibrarySort.UNREAD) order else Item.MultiSort.SORT_NONE
+                total.state = if (sorting == LibrarySort.TOTAL) order else Item.MultiSort.SORT_NONE
+                latestChapter.state =
+                    if (sorting == LibrarySort.LATEST_CHAPTER) order else Item.MultiSort.SORT_NONE
+            }
+
+            override fun onItemClicked(item: Item) {
+                item as Item.MultiStateGroup
+                val prevState = item.state
+
+                item.group.items.forEach {
+                    (it as Item.MultiStateGroup).state =
+                        Item.MultiSort.SORT_NONE
+                }
+                item.state = when (prevState) {
+                    Item.MultiSort.SORT_NONE -> Item.MultiSort.SORT_ASC
+                    Item.MultiSort.SORT_ASC -> Item.MultiSort.SORT_DESC
+                    Item.MultiSort.SORT_DESC -> Item.MultiSort.SORT_ASC
+                    else -> throw Exception("Unknown state")
+                }
+
+                preferences.librarySortingMode().set(
+                    when (item) {
+                        alphabetically -> LibrarySort.ALPHA
+                        lastRead -> LibrarySort.LAST_READ
+                        lastChecked -> LibrarySort.LAST_CHECKED
+                        unread -> LibrarySort.UNREAD
+                        total -> LibrarySort.TOTAL
+                        latestChapter -> LibrarySort.LATEST_CHAPTER
+                        else -> throw Exception("Unknown sorting")
+                    }
+                )
+                preferences.librarySortingAscending().set(item.state == Item.MultiSort.SORT_ASC)
+
+                item.group.items.forEach { adapter.notifyItemChanged(it) }
+            }
+        }
+
+        inner class BadgeGroup : Group {
+            private val downloadBadge =
+                Item.CheckboxGroup(R.string.action_display_download_badge, this)
+            override val header = null
+            override val footer = null
+            override val items = listOf(downloadBadge)
+            override fun initModels() {
+                downloadBadge.checked = preferences.downloadBadge().getOrDefault()
+            }
+
+            override fun onItemClicked(item: Item) {
+                item as Item.CheckboxGroup
+                item.checked = !item.checked
+                preferences.downloadBadge().set((item.checked))
+                adapter.notifyItemChanged(item)
+            }
+        }
+
+        /**
+         * Display group, to show the library as a list or a grid.
+         */
+        inner class DisplayGroup : Group {
+
+            private val grid = Item.Radio(R.string.action_display_grid, this)
+
+            private val list = Item.Radio(R.string.action_display_list, this)
+
+            override val items = listOf(grid, list)
+
+            override val header = Item.Header(R.string.action_display)
+
+            override val footer = null
+
+            override fun initModels() {
+                val asList = preferences.libraryAsList().getOrDefault()
+                grid.checked = !asList
+                list.checked = asList
+            }
+
+            override fun onItemClicked(item: Item) {
+                item as Item.Radio
+                if (item.checked) return
+
+                item.group.items.forEach { (it as Item.Radio).checked = false }
+                item.checked = true
+
+                preferences.libraryAsList().set(item == list)
+
+                item.group.items.forEach { adapter.notifyItemChanged(it) }
+            }
+        }
+    }
+}

+ 6 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt

@@ -86,7 +86,12 @@ class MainActivity : BaseActivity() {
                     R.id.nav_more -> setRoot(MoreController(), id)
                 }
             } else {
-                router.popToRoot()
+                when (id) {
+                    R.id.nav_library -> {
+                        val controller = router.getControllerWithTag(id.toString()) as? LibraryController
+                        controller?.showSettingsSheet()
+                    }
+                }
             }
             true
         }

+ 1 - 2
app/src/main/java/eu/kanade/tachiyomi/widget/ExtendedNavigationView.kt

@@ -20,8 +20,7 @@ open class ExtendedNavigationView @JvmOverloads constructor(
     context: Context,
     attrs: AttributeSet? = null,
     defStyleAttr: Int = 0
-) :
-    SimpleNavigationView(context, attrs, defStyleAttr) {
+) : SimpleNavigationView(context, attrs, defStyleAttr) {
 
     /**
      * Every item of the nav view. Generic items must belong to this list, custom items could be

+ 1 - 2
app/src/main/java/eu/kanade/tachiyomi/widget/SimpleNavigationView.kt

@@ -28,8 +28,7 @@ open class SimpleNavigationView @JvmOverloads constructor(
     context: Context,
     attrs: AttributeSet? = null,
     defStyleAttr: Int = 0
-) :
-    ScrimInsetsFrameLayout(context, attrs, defStyleAttr) {
+) : ScrimInsetsFrameLayout(context, attrs, defStyleAttr) {
 
     /**
      * Max width of the navigation view.

+ 0 - 7
app/src/main/res/layout/library_drawer.xml

@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<eu.kanade.tachiyomi.ui.library.LibraryNavigationView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/nav_view2"
-    android:layout_width="wrap_content"
-    android:layout_height="match_parent"
-    android:layout_gravity="end"
-    android:fitsSystemWindows="false" />