Option to hide categories + added back fastscroller

It's still anchored to the edge of the screen, and locks the filter bar when pressing it
This commit is contained in:
Jay 2020-02-01 18:41:08 -08:00
parent 4d6fb3139d
commit e96fb3c17c
8 changed files with 154 additions and 45 deletions

View File

@ -165,6 +165,8 @@ class PreferencesHelper(val context: Context) {
fun filterTracked() = rxPrefs.getInteger(Keys.filterTrcaked, 0)
fun showCategories() = rxPrefs.getBoolean("show_categories", true)
fun librarySortingMode() = rxPrefs.getInteger(Keys.librarySortingMode, 0)
fun librarySortingAscending() = rxPrefs.getBoolean("library_sorting_ascending", true)

View File

@ -7,6 +7,7 @@ import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.ui.category.CategoryAdapter
import eu.kanade.tachiyomi.util.chop
import eu.kanade.tachiyomi.util.removeArticles
import uy.kohesive.injekt.injectLazy
import java.text.SimpleDateFormat
@ -69,14 +70,36 @@ class LibraryCategoryAdapter(val view: LibraryCategoryView) :
val iFlexible: IFlexible<*>? = getItem(position)
val preferences:PreferencesHelper by injectLazy()
when (preferences.librarySortingMode().getOrDefault()) {
LibrarySort.DRAG_AND_DROP -> {
if (preferences.showCategories().getOrDefault()) {
val title = (iFlexible as LibraryItem).manga.currentTitle()
if (preferences.removeArticles().getOrDefault())
title.removeArticles().substring(0, 1).toUpperCase(Locale.US)
else title.substring(0, 1).toUpperCase(Locale.US)
}
else {
val db:DatabaseHelper by injectLazy()
val category = db.getCategoriesForManga((iFlexible as LibraryItem).manga)
.executeAsBlocking().firstOrNull()?.name
category?.chop(10) ?: "Default"
}
}
LibrarySort.LAST_READ -> {
val db:DatabaseHelper by injectLazy()
val id = (iFlexible as LibraryItem).manga.id ?: return ""
val history = db.getHistoryByMangaId(id).executeAsBlocking()
if (history.firstOrNull() != null)
getShortDate(Date(history.first().last_read))
val last = history.maxBy { it.last_read }
if (last != null)
getShortDate(Date(last.last_read))
else
"Never Read"
"N/A"
}
LibrarySort.UNREAD -> {
val unread = (iFlexible as LibraryItem).manga.unread
if (unread > 0)
unread.toString()
else
"Read"
}
LibrarySort.LAST_UPDATED -> {
val lastUpdate = (iFlexible as LibraryItem).manga.last_update
@ -105,9 +128,9 @@ class LibraryCategoryAdapter(val view: LibraryCategoryView) :
val yearThen = cal2.get(Calendar.YEAR)
return if (yearNow == yearThen)
SimpleDateFormat("MMM").format(date)
SimpleDateFormat("MMM", Locale.getDefault()).format(date)
else
SimpleDateFormat("yyyy").format(date)
SimpleDateFormat("yyyy", Locale.getDefault()).format(date)
}
}

View File

@ -13,15 +13,19 @@ import eu.davidea.flexibleadapter.SelectableAdapter
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Category
import eu.kanade.tachiyomi.data.database.models.LibraryManga
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.ui.category.CategoryAdapter
import eu.kanade.tachiyomi.util.*
import eu.kanade.tachiyomi.util.doOnApplyWindowInsets
import eu.kanade.tachiyomi.util.inflate
import eu.kanade.tachiyomi.util.launchUI
import eu.kanade.tachiyomi.util.plusAssign
import eu.kanade.tachiyomi.util.snack
import eu.kanade.tachiyomi.util.updateLayoutParams
import eu.kanade.tachiyomi.util.updatePaddingRelative
import eu.kanade.tachiyomi.widget.AutofitRecyclerView
import kotlinx.android.synthetic.main.chapters_controller.*
import kotlinx.android.synthetic.main.library_category.view.*
import kotlinx.coroutines.delay
import rx.subscriptions.CompositeSubscription
@ -98,10 +102,12 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
// Disable swipe refresh when view is not at the top
val firstPos = (recycler.layoutManager as LinearLayoutManager)
.findFirstCompletelyVisibleItemPosition()
swipe_refresh.isEnabled = firstPos <= 0
swipe_refresh.isEnabled = firstPos <= 0 && preferences.showCategories().getOrDefault()
}
})
fast_scroller?.gone()
fast_scroller.addOnScrollStateChangeListener {
controller.lockFilterBar(it)
}
recycler.doOnApplyWindowInsets { v, insets, padding ->
v.updatePaddingRelative(bottom = padding.bottom + insets.systemWindowInsetBottom)
@ -185,7 +191,8 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
val filterOff = preferences.filterCompleted().getOrDefault() +
preferences.filterTracked().getOrDefault() +
preferences.filterUnread().getOrDefault() +
preferences.filterCompleted().getOrDefault() == 0
preferences.filterCompleted().getOrDefault() == 0 &&
preferences.showCategories().getOrDefault()
return sortingMode == LibrarySort.DRAG_AND_DROP && filterOff &&
adapter.mode != SelectableAdapter.Mode.MULTI
}
@ -214,6 +221,8 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
// Update the category with its manga.
adapter.setItems(mangaForCategory)
swipe_refresh.isEnabled = preferences.showCategories().getOrDefault()
if (adapter.mode == SelectableAdapter.Mode.MULTI) {
controller.selectedMangas.forEach { manga ->
val position = adapter.indexOf(manga)

View File

@ -54,6 +54,8 @@ import eu.kanade.tachiyomi.util.marginBottom
import eu.kanade.tachiyomi.util.marginTop
import eu.kanade.tachiyomi.util.snack
import eu.kanade.tachiyomi.util.updatePaddingRelative
import eu.kanade.tachiyomi.util.visible
import eu.kanade.tachiyomi.widget.ExtendedNavigationView
import kotlinx.android.synthetic.main.library_controller.*
import kotlinx.android.synthetic.main.main_activity.*
import rx.Subscription
@ -259,9 +261,9 @@ class LibraryController(
navView = view
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, GravityCompat.END)
navView?.onGroupClicked = { group ->
navView?.onGroupClicked = { group, item ->
when (group) {
is LibraryNavigationView.FilterGroup -> onFilterChanged()
is LibraryNavigationView.FilterGroup -> onFilterChanged(item)
is LibraryNavigationView.SortGroup -> onSortChanged()
is LibraryNavigationView.DisplayGroup -> reattachAdapter()
is LibraryNavigationView.BadgeGroup -> onDownloadBadgeChanged()
@ -361,7 +363,12 @@ class LibraryController(
/**
* Called when a filter is changed.
*/
private fun onFilterChanged() {
private fun onFilterChanged(item: ExtendedNavigationView.Item) {
if (item is ExtendedNavigationView.Item.MultiStateGroup && item.resTitle == R.string.categories) {
activity?.invalidateOptionsMenu()
presenter.requestFullUpdate()
return
}
presenter.requestFilterUpdate()
destroyActionModeIfNeeded()
activity?.invalidateOptionsMenu()
@ -417,7 +424,9 @@ class LibraryController(
inflater.inflate(R.menu.library, menu)
val reorganizeItem = menu.findItem(R.id.action_reorganize)
reorganizeItem.isVisible = preferences.librarySortingMode().getOrDefault() == LibrarySort.DRAG_AND_DROP
reorganizeItem.isVisible =
preferences.librarySortingMode().getOrDefault() == LibrarySort.DRAG_AND_DROP &&
preferences.showCategories().getOrDefault()
reorderMenuItem = reorganizeItem
enableReorderItems()
@ -629,7 +638,7 @@ class LibraryController(
val mangas = selectedMangas.toList()
// Hide the default category because it has a different behavior than the ones from db.
val categories = presenter.categories.filter { it.id != 0 }
val categories = presenter.allCategories.filter { it.id != 0 }
// Get indexes of the common categories to preselect.
val commonCategoriesIndexes = presenter.getCommonCategories(mangas)
@ -640,6 +649,17 @@ class LibraryController(
.showDialog(router)
}
fun lockFilterBar(lock: Boolean) {
val drawer = (navView?.parent as? DrawerLayout) ?: return
if (lock) {
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
drawer.closeDrawers()
} else {
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
drawer.visible()
}
}
private fun deleteMangasFromLibrary() {
val mangas = selectedMangas.toList()
presenter.removeMangaFromLibrary(mangas)

View File

@ -3,17 +3,17 @@ package eu.kanade.tachiyomi.ui.library
import android.content.Context
import android.util.AttributeSet
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.ui.catalogue.filter.TriStateItem
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 eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.Companion.STATE_EXCLUDE
import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.Companion.STATE_IGNORE
import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.Companion.STATE_INCLUDE
import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.Companion.STATE_EXCLUDE
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy
@ -42,7 +42,7 @@ class LibraryNavigationView @JvmOverloads constructor(context: Context, attrs: A
/**
* Click listener to notify the parent fragment when an item from a group is clicked.
*/
var onGroupClicked: (Group) -> Unit = {}
var onGroupClicked: (Group, Item) -> Unit = { _, _ -> }
init {
recycler.adapter = adapter
@ -55,7 +55,15 @@ class LibraryNavigationView @JvmOverloads constructor(context: Context, attrs: A
* Returns true if there's at least one filter from [FilterGroup] active.
*/
fun hasActiveFilters(): Boolean {
return (groups[0] as FilterGroup).items.any { it.state != STATE_IGNORE }
return (groups[0] as FilterGroup).items.any {
when (it) {
is Item.TriStateGroup ->
if (it.resTitle == R.string.categories) it.state == STATE_IGNORE
else it.state != STATE_IGNORE
is Item.CheckboxGroup -> it.checked
else -> false
}
}
}
/**
@ -66,7 +74,7 @@ class LibraryNavigationView @JvmOverloads constructor(context: Context, attrs: A
override fun onItemClicked(item: Item) {
if (item is GroupedItem) {
item.group.onItemClicked(item)
onGroupClicked(item.group)
onGroupClicked(item.group, item)
}
}
}
@ -84,9 +92,19 @@ class LibraryNavigationView @JvmOverloads constructor(context: Context, attrs: A
private val tracked = Item.TriStateGroup(R.string.tracked, this)
override val items = if (Injekt.get<TrackManager>().hasLoggedServices())
listOf(downloaded, unread, completed, tracked) else listOf(downloaded, unread,
completed)
private val categories = Item.TriStateGroup(R.string.categories, this)
override val items:List<Item> = {
val list = mutableListOf<Item>()
if (Injekt.get<DatabaseHelper>().getCategories().executeAsBlocking().isNotEmpty())
list.add(categories)
list.add(downloaded)
list.add(unread)
list.add(completed)
if (Injekt.get<TrackManager>().hasLoggedServices())
list.add(tracked)
list
}()
override val header = Item.Header(R.string.action_filter)
@ -94,6 +112,8 @@ class LibraryNavigationView @JvmOverloads constructor(context: Context, attrs: A
override fun initModels() {
try {
categories.state = if (preferences.showCategories().getOrDefault()) STATE_INCLUDE
else STATE_IGNORE
downloaded.state = preferences.filterDownloaded().getOrDefault()
unread.state = preferences.filterUnread().getOrDefault()
completed.state = preferences.filterCompleted().getOrDefault()
@ -105,20 +125,31 @@ class LibraryNavigationView @JvmOverloads constructor(context: Context, attrs: A
}
override fun onItemClicked(item: Item) {
item as Item.TriStateGroup
val newState = when (item.state) {
STATE_IGNORE -> STATE_INCLUDE
STATE_INCLUDE -> STATE_EXCLUDE
else -> STATE_IGNORE
if (item == categories) {
item as Item.TriStateGroup
val newState = when (item.state) {
STATE_IGNORE -> STATE_INCLUDE
else -> STATE_IGNORE
}
item.state = newState
when (item) {
categories -> preferences.showCategories().set(item.state == STATE_INCLUDE)
}
}
item.state = newState
when (item) {
downloaded -> preferences.filterDownloaded().set(item.state)
unread -> preferences.filterUnread().set(item.state)
completed -> preferences.filterCompleted().set(item.state)
tracked -> preferences.filterTracked().set(item.state)
else if (item is Item.TriStateGroup) {
val newState = when (item.state) {
STATE_IGNORE -> STATE_INCLUDE
STATE_INCLUDE -> STATE_EXCLUDE
else -> STATE_IGNORE
}
item.state = newState
when (item) {
downloaded -> preferences.filterDownloaded().set(item.state)
unread -> preferences.filterUnread().set(item.state)
completed -> preferences.filterCompleted().set(item.state)
tracked -> preferences.filterTracked().set(item.state)
}
}
adapter.notifyItemChanged(item)
}
}

View File

@ -70,6 +70,8 @@ class LibraryPresenter(
var categories: List<Category> = emptyList()
private set
var allCategories: List<Category> = emptyList()
private set
/**
* Relay used to apply the UI filters to the last emission of the library.
*/
@ -264,7 +266,11 @@ class LibraryPresenter(
else -> 0
}
}
else 0
else {
val category = catListing.find { it.id == i1.manga.category }
val category2 = catListing.find { it.id == i2.manga.category }
category?.order?.compareTo(category2?.order ?: 0) ?: 0
}
}
else -> 0
}
@ -296,12 +302,15 @@ class LibraryPresenter(
*/
private fun getLibraryObservable(): Observable<Library> {
return Observable.combineLatest(getCategoriesObservable(), getLibraryMangasObservable()) { dbCategories, libraryManga ->
val categories = if (libraryManga.containsKey(0)) arrayListOf(Category.createDefault
(context)) + dbCategories
val categories = if (libraryManga.containsKey(0))
arrayListOf(Category.createDefault(context)) + dbCategories
else dbCategories
this.categories = categories
Library(categories, libraryManga)
this.allCategories = categories
this.categories = if (!preferences.showCategories().getOrDefault())
arrayListOf(Category.createDefault(context))
else categories
Library(this.categories, libraryManga)
}
}
@ -324,7 +333,13 @@ class LibraryPresenter(
val libraryAsList = preferences.libraryAsList()
return db.getLibraryMangas().asRxObservable()
.map { list ->
list.map { LibraryItem(it, libraryAsList) }.groupBy { it.manga.category }
if (preferences.showCategories().getOrDefault()) {
list.map { LibraryItem(it, libraryAsList) }.groupBy { it.manga.category }
}
else {
list.distinctBy { it.id }.map { LibraryItem(it, libraryAsList)}.groupBy {
0 }
}
}
}
@ -349,6 +364,11 @@ class LibraryPresenter(
sortTriggerRelay.call(Unit)
}
fun requestFullUpdate() {
librarySubscription?.unsubscribe()
subscribeLibrary()
}
/**
* Called when a manga is opened.
*/

View File

@ -5,11 +5,14 @@ import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup
import android.widget.*
import android.widget.CheckBox
import android.widget.CheckedTextView
import android.widget.EditText
import android.widget.RadioButton
import android.widget.Spinner
import android.widget.TextView
import androidx.appcompat.widget.TintTypedArray
import androidx.core.view.ViewCompat
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.R
import com.google.android.material.internal.ScrimInsetsFrameLayout
import com.google.android.material.textfield.TextInputLayout

View File

@ -18,5 +18,6 @@
android:layout_height="match_parent"
android:layout_gravity="end"
app:fastScrollerBubbleEnabled="true"
app:fastScrollerIgnoreTouchesOutsideHandle="true"
tools:visibility="visible" />
</eu.kanade.tachiyomi.ui.library.LibraryCategoryView>