Refactor library sheet into tabs
This commit is contained in:
parent
fba3ed2244
commit
9f974c9401
5 changed files with 166 additions and 84 deletions
|
@ -166,10 +166,10 @@ class LibraryController(
|
||||||
|
|
||||||
settingsSheet = LibrarySettingsSheet(activity!!) { group ->
|
settingsSheet = LibrarySettingsSheet(activity!!) { group ->
|
||||||
when (group) {
|
when (group) {
|
||||||
is LibrarySettingsSheet.Settings.FilterGroup -> onFilterChanged()
|
is LibrarySettingsSheet.FilterSettings.FilterGroup -> onFilterChanged()
|
||||||
is LibrarySettingsSheet.Settings.SortGroup -> onSortChanged()
|
is LibrarySettingsSheet.SortSettings.SortGroup -> onSortChanged()
|
||||||
is LibrarySettingsSheet.Settings.DisplayGroup -> reattachAdapter()
|
is LibrarySettingsSheet.DisplaySettings.DisplayGroup -> reattachAdapter()
|
||||||
is LibrarySettingsSheet.Settings.BadgeGroup -> onDownloadBadgeChanged()
|
is LibrarySettingsSheet.DisplaySettings.BadgeGroup -> onDownloadBadgeChanged()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,78 +3,73 @@ package eu.kanade.tachiyomi.ui.library
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
|
import eu.kanade.tachiyomi.databinding.LibrarySettingsSheetBinding
|
||||||
import eu.kanade.tachiyomi.widget.ExtendedNavigationView
|
import eu.kanade.tachiyomi.widget.ExtendedNavigationView
|
||||||
|
import eu.kanade.tachiyomi.widget.ViewPagerAdapter
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
class LibrarySettingsSheet(
|
class LibrarySettingsSheet(
|
||||||
activity: Activity,
|
private val activity: Activity,
|
||||||
onGroupClickListener: (ExtendedNavigationView.Group) -> Unit
|
private val onGroupClickListener: (ExtendedNavigationView.Group) -> Unit
|
||||||
) : BottomSheetDialog(activity) {
|
) : BottomSheetDialog(activity) {
|
||||||
|
|
||||||
private var navView: Settings
|
private val filterSettings = FilterSettings(activity)
|
||||||
|
private val tabItems = listOf(
|
||||||
|
Pair(R.string.action_filter, filterSettings),
|
||||||
|
Pair(R.string.action_sort, SortSettings(activity)),
|
||||||
|
Pair(R.string.action_display, DisplaySettings(activity))
|
||||||
|
)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
navView = Settings(activity)
|
val binding: LibrarySettingsSheetBinding = LibrarySettingsSheetBinding.inflate(activity.layoutInflater)
|
||||||
navView.onGroupClicked = onGroupClickListener
|
|
||||||
|
|
||||||
setContentView(navView)
|
val adapter = LibrarySettingsSheetAdapter()
|
||||||
|
binding.librarySettingsPager.adapter = adapter
|
||||||
|
binding.librarySettingsTabs.setupWithViewPager(binding.librarySettingsPager)
|
||||||
|
|
||||||
|
setContentView(binding.root)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun hasActiveFilters(): Boolean {
|
fun hasActiveFilters(): Boolean {
|
||||||
return navView.hasActiveFilters()
|
return filterSettings.hasActiveFilters()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private inner class LibrarySettingsSheetAdapter : ViewPagerAdapter() {
|
||||||
* 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()
|
override fun createView(container: ViewGroup, position: Int): View {
|
||||||
|
val view = tabItems[position].second
|
||||||
|
view.onGroupClicked = onGroupClickListener
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
override fun getCount(): Int {
|
||||||
* List of groups shown in the view.
|
return tabItems.size
|
||||||
*/
|
}
|
||||||
private val groups = listOf(FilterGroup(), SortGroup(), DisplayGroup(), BadgeGroup())
|
|
||||||
|
|
||||||
/**
|
override fun getPageTitle(position: Int): CharSequence {
|
||||||
* Adapter instance.
|
return activity.resources!!.getString(tabItems[position].first)
|
||||||
*/
|
}
|
||||||
private val adapter = Adapter(groups.map { it.createItems() }.flatten())
|
}
|
||||||
|
|
||||||
/**
|
inner class FilterSettings @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
||||||
* Click listener to notify the parent fragment when an item from a group is clicked.
|
Settings(context, attrs) {
|
||||||
*/
|
|
||||||
var onGroupClicked: (Group) -> Unit = {}
|
private val filterGroup = FilterGroup()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
recycler.adapter = adapter
|
addGroups(listOf(filterGroup))
|
||||||
addView(recycler)
|
|
||||||
|
|
||||||
groups.forEach { it.initModels() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if there's at least one filter from [FilterGroup] active.
|
* Returns true if there's at least one filter from [FilterGroup] active.
|
||||||
*/
|
*/
|
||||||
fun hasActiveFilters(): Boolean {
|
fun hasActiveFilters(): Boolean {
|
||||||
return (groups[0] as FilterGroup).items.any { it.checked }
|
return 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -83,16 +78,12 @@ class LibrarySettingsSheet(
|
||||||
inner class FilterGroup : Group {
|
inner class FilterGroup : Group {
|
||||||
|
|
||||||
private val downloaded = Item.CheckboxGroup(R.string.action_filter_downloaded, this)
|
private val downloaded = Item.CheckboxGroup(R.string.action_filter_downloaded, this)
|
||||||
|
|
||||||
private val unread = Item.CheckboxGroup(R.string.action_filter_unread, this)
|
private val unread = Item.CheckboxGroup(R.string.action_filter_unread, this)
|
||||||
|
|
||||||
private val completed = Item.CheckboxGroup(R.string.completed, this)
|
private val completed = Item.CheckboxGroup(R.string.completed, this)
|
||||||
|
|
||||||
|
override val header = null
|
||||||
override val items = listOf(downloaded, unread, completed)
|
override val items = listOf(downloaded, unread, completed)
|
||||||
|
override val footer = null
|
||||||
override val header = Item.Header(R.string.action_filter)
|
|
||||||
|
|
||||||
override val footer = Item.Separator()
|
|
||||||
|
|
||||||
override fun initModels() {
|
override fun initModels() {
|
||||||
downloaded.checked = preferences.downloadedOnly().get() || preferences.filterDownloaded().get()
|
downloaded.checked = preferences.downloadedOnly().get() || preferences.filterDownloaded().get()
|
||||||
|
@ -113,6 +104,14 @@ class LibrarySettingsSheet(
|
||||||
adapter.notifyItemChanged(item)
|
adapter.notifyItemChanged(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class SortSettings @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
||||||
|
Settings(context, attrs) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
addGroups(listOf(SortGroup()))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sorting group (alphabetically, by last read, ...) and ascending or descending.
|
* Sorting group (alphabetically, by last read, ...) and ascending or descending.
|
||||||
|
@ -120,23 +119,16 @@ class LibrarySettingsSheet(
|
||||||
inner class SortGroup : Group {
|
inner class SortGroup : Group {
|
||||||
|
|
||||||
private val alphabetically = Item.MultiSort(R.string.action_sort_alpha, this)
|
private val alphabetically = Item.MultiSort(R.string.action_sort_alpha, this)
|
||||||
|
|
||||||
private val total = Item.MultiSort(R.string.action_sort_total, 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 lastRead = Item.MultiSort(R.string.action_sort_last_read, this)
|
||||||
|
|
||||||
private val lastChecked = Item.MultiSort(R.string.action_sort_last_checked, 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 unread = Item.MultiSort(R.string.action_filter_unread, this)
|
||||||
|
|
||||||
private val latestChapter = Item.MultiSort(R.string.action_sort_latest_chapter, this)
|
private val latestChapter = Item.MultiSort(R.string.action_sort_latest_chapter, this)
|
||||||
|
|
||||||
|
override val header = null
|
||||||
override val items =
|
override val items =
|
||||||
listOf(alphabetically, lastRead, lastChecked, unread, total, latestChapter)
|
listOf(alphabetically, lastRead, lastChecked, unread, total, latestChapter)
|
||||||
|
override val footer = null
|
||||||
override val header = Item.Header(R.string.action_sort)
|
|
||||||
|
|
||||||
override val footer = Item.Separator()
|
|
||||||
|
|
||||||
override fun initModels() {
|
override fun initModels() {
|
||||||
val sorting = preferences.librarySortingMode().get()
|
val sorting = preferences.librarySortingMode().get()
|
||||||
|
@ -187,23 +179,13 @@ class LibrarySettingsSheet(
|
||||||
item.group.items.forEach { adapter.notifyItemChanged(it) }
|
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().get()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onItemClicked(item: Item) {
|
inner class DisplaySettings @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
||||||
item as Item.CheckboxGroup
|
Settings(context, attrs) {
|
||||||
item.checked = !item.checked
|
|
||||||
preferences.downloadBadge().set((item.checked))
|
init {
|
||||||
adapter.notifyItemChanged(item)
|
addGroups(listOf(DisplayGroup(), BadgeGroup()))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -212,13 +194,10 @@ class LibrarySettingsSheet(
|
||||||
inner class DisplayGroup : Group {
|
inner class DisplayGroup : Group {
|
||||||
|
|
||||||
private val grid = Item.Radio(R.string.action_display_grid, this)
|
private val grid = Item.Radio(R.string.action_display_grid, this)
|
||||||
|
|
||||||
private val list = Item.Radio(R.string.action_display_list, this)
|
private val list = Item.Radio(R.string.action_display_list, this)
|
||||||
|
|
||||||
|
override val header = null
|
||||||
override val items = listOf(grid, list)
|
override val items = listOf(grid, list)
|
||||||
|
|
||||||
override val header = Item.Header(R.string.action_display)
|
|
||||||
|
|
||||||
override val footer = null
|
override val footer = null
|
||||||
|
|
||||||
override fun initModels() {
|
override fun initModels() {
|
||||||
|
@ -239,5 +218,60 @@ class LibrarySettingsSheet(
|
||||||
item.group.items.forEach { adapter.notifyItemChanged(it) }
|
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 items = listOf(downloadBadge)
|
||||||
|
override val footer = null
|
||||||
|
|
||||||
|
override fun initModels() {
|
||||||
|
downloadBadge.checked = preferences.downloadBadge().get()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onItemClicked(item: Item) {
|
||||||
|
item as Item.CheckboxGroup
|
||||||
|
item.checked = !item.checked
|
||||||
|
preferences.downloadBadge().set((item.checked))
|
||||||
|
adapter.notifyItemChanged(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open inner class Settings(context: Context, attrs: AttributeSet?) :
|
||||||
|
ExtendedNavigationView(context, attrs) {
|
||||||
|
|
||||||
|
val preferences: PreferencesHelper by injectLazy()
|
||||||
|
lateinit var adapter: Adapter
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Click listener to notify the parent fragment when an item from a group is clicked.
|
||||||
|
*/
|
||||||
|
var onGroupClicked: (Group) -> Unit = {}
|
||||||
|
|
||||||
|
init {
|
||||||
|
addView(recycler)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addGroups(groups: List<Group>) {
|
||||||
|
adapter = Adapter(groups.map { it.createItems() }.flatten())
|
||||||
|
recycler.adapter = adapter
|
||||||
|
|
||||||
|
groups.forEach { it.initModels() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,9 +19,6 @@ class ReaderPageSheet(
|
||||||
private val page: ReaderPage
|
private val page: ReaderPage
|
||||||
) : BottomSheetDialog(activity) {
|
) : BottomSheetDialog(activity) {
|
||||||
|
|
||||||
/**
|
|
||||||
* View used on this sheet.
|
|
||||||
*/
|
|
||||||
private val view = activity.layoutInflater.inflate(R.layout.reader_page_sheet, null)
|
private val view = activity.layoutInflater.inflate(R.layout.reader_page_sheet, null)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
package eu.kanade.tachiyomi.widget
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import androidx.viewpager.widget.ViewPager
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A [ViewPager] that sets its height to the maximum height of its children.
|
||||||
|
* This is a way to mimic WRAP_CONTENT for its height.
|
||||||
|
*/
|
||||||
|
class MaxHeightViewPager(context: Context, attrs: AttributeSet?) : ViewPager(context, attrs) {
|
||||||
|
|
||||||
|
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||||
|
var measuredHeight = heightMeasureSpec
|
||||||
|
|
||||||
|
var height = 0
|
||||||
|
for (i in 0 until childCount) {
|
||||||
|
val child = getChildAt(i)
|
||||||
|
child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED))
|
||||||
|
val h = child.measuredHeight
|
||||||
|
if (h > height) height = h
|
||||||
|
}
|
||||||
|
|
||||||
|
if (height != 0) {
|
||||||
|
measuredHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
|
||||||
|
}
|
||||||
|
|
||||||
|
super.onMeasure(widthMeasureSpec, measuredHeight)
|
||||||
|
}
|
||||||
|
}
|
21
app/src/main/res/layout/library_settings_sheet.xml
Normal file
21
app/src/main/res/layout/library_settings_sheet.xml
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<com.google.android.material.tabs.TabLayout
|
||||||
|
android:id="@+id/library_settings_tabs"
|
||||||
|
style="@style/Theme.Widget.Tabs"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:tabGravity="fill"
|
||||||
|
app:tabMode="fixed" />
|
||||||
|
|
||||||
|
<eu.kanade.tachiyomi.widget.MaxHeightViewPager
|
||||||
|
android:id="@+id/library_settings_pager"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
Reference in a new issue