mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-12-23 11:11:51 +01:00
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:
parent
4d6fb3139d
commit
e96fb3c17c
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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,7 +125,18 @@ class LibraryNavigationView @JvmOverloads constructor(context: Context, attrs: A
|
||||
}
|
||||
|
||||
override fun onItemClicked(item: Item) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
else if (item is Item.TriStateGroup) {
|
||||
val newState = when (item.state) {
|
||||
STATE_IGNORE -> STATE_INCLUDE
|
||||
STATE_INCLUDE -> STATE_EXCLUDE
|
||||
@ -118,7 +149,7 @@ class LibraryNavigationView @JvmOverloads constructor(context: Context, attrs: A
|
||||
completed -> preferences.filterCompleted().set(item.state)
|
||||
tracked -> preferences.filterTracked().set(item.state)
|
||||
}
|
||||
|
||||
}
|
||||
adapter.notifyItemChanged(item)
|
||||
}
|
||||
}
|
||||
|
@ -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,8 +333,14 @@ class LibraryPresenter(
|
||||
val libraryAsList = preferences.libraryAsList()
|
||||
return db.getLibraryMangas().asRxObservable()
|
||||
.map { list ->
|
||||
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.
|
||||
*/
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user