Option to collapse dynamic categories

This commit is contained in:
Jays2Kings 2021-04-19 00:19:38 -04:00
parent 94a90c6cec
commit 4bb6dbf528
6 changed files with 106 additions and 51 deletions

View File

@ -69,6 +69,14 @@ operator fun <T> com.tfcporciuncula.flow.Preference<Set<T>>.minusAssign(item: T)
set(get() - item) set(get() - item)
} }
operator fun <T> com.tfcporciuncula.flow.Preference<Set<T>>.plusAssign(item: Collection<T>) {
set(get() + item)
}
operator fun <T> com.tfcporciuncula.flow.Preference<Set<T>>.minusAssign(item: Collection<T>) {
set(get() - item)
}
class PreferencesHelper(val context: Context) { class PreferencesHelper(val context: Context) {
private val prefs = PreferenceManager.getDefaultSharedPreferences(context) private val prefs = PreferenceManager.getDefaultSharedPreferences(context)
@ -270,6 +278,8 @@ class PreferencesHelper(val context: Context) {
fun collapsedCategories() = rxPrefs.getStringSet("collapsed_categories", mutableSetOf()) fun collapsedCategories() = rxPrefs.getStringSet("collapsed_categories", mutableSetOf())
fun collapsedDynamicCategories() = flowPrefs.getStringSet("collapsed_dynamic_categories", mutableSetOf())
fun hiddenSources() = flowPrefs.getStringSet("hidden_catalogues", mutableSetOf()) fun hiddenSources() = flowPrefs.getStringSet("hidden_catalogues", mutableSetOf())
fun pinnedCatalogues() = rxPrefs.getStringSet("pinned_catalogues", emptySet()) fun pinnedCatalogues() = rxPrefs.getStringSet("pinned_catalogues", emptySet())

View File

@ -918,10 +918,7 @@ class LibraryController(
) )
adapter.isLongPressDragEnabled = canDrag() adapter.isLongPressDragEnabled = canDrag()
binding.categoryRecycler.setCategories(presenter.categories) binding.categoryRecycler.setCategories(presenter.categories)
displaySheet?.setExpandText( displaySheet?.setExpandText(canCollapseOrExpandCategory())
showExpanded = !singleCategory && presenter.showAllCategories,
allExpanded = preferences.collapsedCategories().getOrDefault().isNotEmpty()
)
if (shouldScrollToTop) { if (shouldScrollToTop) {
binding.libraryGridRecycler.recycler.scrollToPosition(0) binding.libraryGridRecycler.recycler.scrollToPosition(0)
shouldScrollToTop = false shouldScrollToTop = false
@ -1382,6 +1379,19 @@ class LibraryController(
presenter.toggleCategoryVisibility(catId) presenter.toggleCategoryVisibility(catId)
} }
/**
* Nullable Boolean to tell is all is collapsed/expanded/applicable
* true = all categories are expanded
* false = all or some categories are collapsed
* null = is in single category mode
*/
fun canCollapseOrExpandCategory(): Boolean? {
if (singleCategory || !presenter.showAllCategories) {
return null
}
return presenter.allCategoriesExpanded()
}
override fun manageCategory(position: Int) { override fun manageCategory(position: Int) {
val category = (adapter.getItem(position) as? LibraryHeaderItem)?.category ?: return val category = (adapter.getItem(position) as? LibraryHeaderItem)?.category ?: return
if (!category.isDynamic) { if (!category.isDynamic) {

View File

@ -80,14 +80,6 @@ class LibraryHeaderHolder(val view: View, private val adapter: LibraryCategoryAd
} }
val category = item.category val category = item.category
if (category.isDynamic) {
binding.categoryHeaderLayout.background = null
binding.categoryTitle.background = null
} else {
binding.categoryHeaderLayout.setBackgroundResource(R.drawable.list_item_selector)
binding.categoryTitle.setBackgroundResource(R.drawable.square_ripple)
}
if (category.isAlone && !category.isDynamic) binding.categoryTitle.text = "" if (category.isAlone && !category.isDynamic) binding.categoryTitle.text = ""
else binding.categoryTitle.text = category.name else binding.categoryTitle.text = category.name
if (category.sourceId != null) { if (category.sourceId != null) {
@ -115,7 +107,7 @@ class LibraryHeaderHolder(val view: View, private val adapter: LibraryCategoryAd
when { when {
adapter.mode == SelectableAdapter.Mode.MULTI -> { adapter.mode == SelectableAdapter.Mode.MULTI -> {
binding.checkbox.visibleIf(!category.isHidden) binding.checkbox.visibleIf(!category.isHidden)
binding.collapseArrow.visibleIf(category.isHidden && !adapter.isSingleCategory && !category.isDynamic) binding.collapseArrow.visibleIf(category.isHidden && !adapter.isSingleCategory)
binding.updateButton.gone() binding.updateButton.gone()
binding.catProgress.gone() binding.catProgress.gone()
setSelection() setSelection()
@ -127,13 +119,13 @@ class LibraryHeaderHolder(val view: View, private val adapter: LibraryCategoryAd
binding.updateButton.gone() binding.updateButton.gone()
} }
LibraryUpdateService.categoryInQueue(category.id) -> { LibraryUpdateService.categoryInQueue(category.id) -> {
binding.collapseArrow.visibleIf(!adapter.isSingleCategory && !category.isDynamic) binding.collapseArrow.visibleIf(!adapter.isSingleCategory)
binding.checkbox.gone() binding.checkbox.gone()
binding.catProgress.visible() binding.catProgress.visible()
binding.updateButton.invisible() binding.updateButton.invisible()
} }
else -> { else -> {
binding.collapseArrow.visibleIf(!adapter.isSingleCategory && !category.isDynamic) binding.collapseArrow.visibleIf(!adapter.isSingleCategory)
binding.catProgress.gone() binding.catProgress.gone()
binding.checkbox.gone() binding.checkbox.gone()
binding.updateButton.visibleIf(!adapter.isSingleCategory) binding.updateButton.visibleIf(!adapter.isSingleCategory)

View File

@ -11,6 +11,8 @@ import eu.kanade.tachiyomi.data.database.models.MangaCategory
import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.data.preference.minusAssign
import eu.kanade.tachiyomi.data.preference.plusAssign
import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.source.LocalSource import eu.kanade.tachiyomi.source.LocalSource
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
@ -581,12 +583,13 @@ class LibraryPresenter(
} }
BY_SOURCE -> { BY_SOURCE -> {
val source = sourceManager.getOrStub(manga.source) val source = sourceManager.getOrStub(manga.source)
listOf(LibraryItem(manga, makeOrGetHeader("${source.name}◘•◘${source.id}"))) listOf(LibraryItem(manga, makeOrGetHeader("${source.name}$sourceSplitter${source.id}")))
} }
else -> listOf(LibraryItem(manga, makeOrGetHeader(mapStatus(manga.status)))) else -> listOf(LibraryItem(manga, makeOrGetHeader(mapStatus(manga.status))))
} }
}.flatten() }.flatten().toMutableList()
val hiddenDynamics = preferences.collapsedDynamicCategories().get()
val headers = tagItems.map { item -> val headers = tagItems.map { item ->
Category.createCustom( Category.createCustom(
item.key, item.key,
@ -594,11 +597,12 @@ class LibraryPresenter(
preferences.librarySortingAscending().getOrDefault() preferences.librarySortingAscending().getOrDefault()
).apply { ).apply {
id = item.value.catId id = item.value.catId
if (name.contains("◘•◘")) { if (name.contains(sourceSplitter)) {
val split = name.split("◘•◘") val split = name.split(sourceSplitter)
name = split.first() name = split.first()
sourceId = split.last().toLongOrNull() sourceId = split.last().toLongOrNull()
} }
isHidden = getDynamicCategoryName(this) in hiddenDynamics
} }
}.sortedBy { }.sortedBy {
if (groupType == BY_TRACK_STATUS) { if (groupType == BY_TRACK_STATUS) {
@ -607,6 +611,22 @@ class LibraryPresenter(
it.name it.name
} }
} }
headers.forEach { category ->
val catId = category.id ?: return@forEach
val headerItem = tagItems[if (category.sourceId != null) "${category.name}$sourceSplitter${category.sourceId}" else category.name]
if (category.isHidden) {
val mangaToRemove = items.filter { it.header.catId == catId }
val mergedTitle = mangaToRemove.joinToString("-") {
it.manga.title + "-" + it.manga.author
}
sectionedLibraryItems[catId] = mangaToRemove
items.removeAll { it.header.catId == catId }
if (headerItem != null) items.add(
LibraryItem(LibraryManga.createHide(catId, mergedTitle), headerItem)
)
}
}
headers.forEachIndexed { index, category -> category.order = index } headers.forEachIndexed { index, category -> category.order = index }
return items to headers return items to headers
} }
@ -858,7 +878,8 @@ class LibraryPresenter(
} }
fun toggleCategoryVisibility(categoryId: Int) { fun toggleCategoryVisibility(categoryId: Int) {
if (categories.find { it.id == categoryId }?.isDynamic == true) return // if (categories.find { it.id == categoryId }?.isDynamic == true) return
if (groupType == BY_DEFAULT) {
val categoriesHidden = preferences.collapsedCategories().getOrDefault().mapNotNull { val categoriesHidden = preferences.collapsedCategories().getOrDefault().mapNotNull {
it.toIntOrNull() it.toIntOrNull()
}.toMutableSet() }.toMutableSet()
@ -867,19 +888,51 @@ class LibraryPresenter(
} else { } else {
categoriesHidden.add(categoryId) categoriesHidden.add(categoryId)
} }
preferences.collapsedCategories().set(categoriesHidden.map { it.toString() }.toMutableSet()) preferences.collapsedCategories()
.set(categoriesHidden.map { it.toString() }.toMutableSet())
} else {
val categoriesHidden = preferences.collapsedDynamicCategories().get().toMutableSet()
val category = getCategory(categoryId)
val dynamicName = getDynamicCategoryName(category)
if (dynamicName in categoriesHidden) {
categoriesHidden.remove(dynamicName)
} else {
categoriesHidden.add(dynamicName)
}
preferences.collapsedDynamicCategories().set(categoriesHidden)
}
getLibrary() getLibrary()
} }
private fun getDynamicCategoryName(category: Category): String =
groupType.toString() + dynamicCategorySplitter + (category.sourceId?.toString() ?: category.name)
fun toggleAllCategoryVisibility() { fun toggleAllCategoryVisibility() {
if (preferences.collapsedCategories().getOrDefault().isEmpty()) { if (groupType == BY_DEFAULT) {
preferences.collapsedCategories().set(allCategories.map { it.id.toString() }.toMutableSet()) if (allCategoriesExpanded()) {
preferences.collapsedCategories()
.set(allCategories.map { it.id.toString() }.toMutableSet())
} else { } else {
preferences.collapsedCategories().set(mutableSetOf()) preferences.collapsedCategories().set(mutableSetOf())
} }
} else {
if (allCategoriesExpanded()) {
preferences.collapsedDynamicCategories() += categories.map { getDynamicCategoryName(it) }
} else {
preferences.collapsedDynamicCategories() -= categories.map { getDynamicCategoryName(it) }
}
}
getLibrary() getLibrary()
} }
fun allCategoriesExpanded(): Boolean {
return if (groupType == BY_DEFAULT) {
preferences.collapsedCategories().getOrDefault().isEmpty()
} else {
categories.none { it.isHidden }
}
}
/** download All unread */ /** download All unread */
fun downloadUnread(mangaList: List<Manga>) { fun downloadUnread(mangaList: List<Manga>) {
scope.launch { scope.launch {
@ -925,6 +978,8 @@ class LibraryPresenter(
companion object { companion object {
private var lastLibraryItems: List<LibraryItem>? = null private var lastLibraryItems: List<LibraryItem>? = null
private var lastCategories: List<Category>? = null private var lastCategories: List<Category>? = null
private const val sourceSplitter = "◘•◘"
private const val dynamicCategorySplitter = "▄╪\t▄╪\t"
/** Give library manga to a date added based on min chapter fetch */ /** Give library manga to a date added based on min chapter fetch */
fun updateDB() { fun updateDB() {

View File

@ -49,13 +49,11 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
} }
} }
fun showExpandCategories(show: Boolean) { fun setExpandText(allExpanded: Boolean?, animated: Boolean = true) {
binding.expandCollapseCategories.isVisible = show binding.expandCollapseCategories.isVisible = allExpanded != null
} allExpanded ?: return
fun setExpandText(expand: Boolean, animated: Boolean = true) {
binding.expandCollapseCategories.setText( binding.expandCollapseCategories.setText(
if (expand) { if (!allExpanded) {
R.string.expand_all_categories R.string.expand_all_categories
} else { } else {
R.string.collapse_all_categories R.string.collapse_all_categories
@ -63,7 +61,7 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
) )
if (animated) { if (animated) {
binding.expandCollapseCategories.setIconResource( binding.expandCollapseCategories.setIconResource(
if (expand) { if (!allExpanded) {
R.drawable.anim_expand_less_to_more R.drawable.anim_expand_less_to_more
} else { } else {
R.drawable.anim_expand_more_to_less R.drawable.anim_expand_more_to_less
@ -72,7 +70,7 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
(binding.expandCollapseCategories.icon as? AnimatedVectorDrawable)?.start() (binding.expandCollapseCategories.icon as? AnimatedVectorDrawable)?.start()
} else { } else {
binding.expandCollapseCategories.setIconResource( binding.expandCollapseCategories.setIconResource(
if (expand) { if (!allExpanded) {
R.drawable.ic_expand_more_24dp R.drawable.ic_expand_more_24dp
} else { } else {
R.drawable.ic_expand_less_24dp R.drawable.ic_expand_less_24dp

View File

@ -6,15 +6,11 @@ import androidx.core.content.ContextCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
import com.bluelinelabs.conductor.Controller import com.bluelinelabs.conductor.Controller
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.ui.library.LibraryController import eu.kanade.tachiyomi.ui.library.LibraryController
import eu.kanade.tachiyomi.ui.setting.SettingsLibraryController import eu.kanade.tachiyomi.ui.setting.SettingsLibraryController
import eu.kanade.tachiyomi.util.view.compatToolTipText import eu.kanade.tachiyomi.util.view.compatToolTipText
import eu.kanade.tachiyomi.util.view.withFadeTransaction import eu.kanade.tachiyomi.util.view.withFadeTransaction
import eu.kanade.tachiyomi.widget.TabbedBottomSheetDialog import eu.kanade.tachiyomi.widget.TabbedBottomSheetDialog
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
open class TabbedLibraryDisplaySheet(val controller: Controller) : open class TabbedLibraryDisplaySheet(val controller: Controller) :
TabbedBottomSheetDialog(controller.activity!!) { TabbedBottomSheetDialog(controller.activity!!) {
@ -43,21 +39,15 @@ open class TabbedLibraryDisplaySheet(val controller: Controller) :
} }
if (controller is LibraryController) { if (controller is LibraryController) {
setExpandText( setExpandText(controller.canCollapseOrExpandCategory(), false)
!controller.singleCategory && controller.presenter.showAllCategories,
Injekt.get<PreferencesHelper>().collapsedCategories().getOrDefault().isNotEmpty(),
false
)
} else { } else {
setExpandText(showExpanded = false, allExpanded = false) setExpandText(null)
categoryView.binding.addCategoriesButton.isVisible = false categoryView.binding.addCategoriesButton.isVisible = false
} }
} }
fun setExpandText(showExpanded: Boolean, allExpanded: Boolean, animated: Boolean = true) { fun setExpandText(allExpanded: Boolean?, animated: Boolean = true) =
categoryView.showExpandCategories(showExpanded)
categoryView.setExpandText(allExpanded, animated) categoryView.setExpandText(allExpanded, animated)
}
override fun dismiss() { override fun dismiss() {
super.dismiss() super.dismiss()