Refactor library sheet into tabs

This commit is contained in:
arkon 2020-04-24 18:15:37 -04:00
parent fba3ed2244
commit 9f974c9401
5 changed files with 166 additions and 84 deletions

View file

@ -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()
} }
} }
} }

View file

@ -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 { inner class DisplaySettings @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
private val downloadBadge = Settings(context, attrs) {
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) { init {
item as Item.CheckboxGroup addGroups(listOf(DisplayGroup(), BadgeGroup()))
item.checked = !item.checked
preferences.downloadBadge().set((item.checked))
adapter.notifyItemChanged(item)
}
} }
/** /**
@ -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)
}
}
}
} }
} }

View file

@ -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 {

View file

@ -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)
}
}

View 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>