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)
}
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) {
private val prefs = PreferenceManager.getDefaultSharedPreferences(context)
@ -270,6 +278,8 @@ class PreferencesHelper(val context: Context) {
fun collapsedCategories() = rxPrefs.getStringSet("collapsed_categories", mutableSetOf())
fun collapsedDynamicCategories() = flowPrefs.getStringSet("collapsed_dynamic_categories", mutableSetOf())
fun hiddenSources() = flowPrefs.getStringSet("hidden_catalogues", mutableSetOf())
fun pinnedCatalogues() = rxPrefs.getStringSet("pinned_catalogues", emptySet())

View File

@ -918,10 +918,7 @@ class LibraryController(
)
adapter.isLongPressDragEnabled = canDrag()
binding.categoryRecycler.setCategories(presenter.categories)
displaySheet?.setExpandText(
showExpanded = !singleCategory && presenter.showAllCategories,
allExpanded = preferences.collapsedCategories().getOrDefault().isNotEmpty()
)
displaySheet?.setExpandText(canCollapseOrExpandCategory())
if (shouldScrollToTop) {
binding.libraryGridRecycler.recycler.scrollToPosition(0)
shouldScrollToTop = false
@ -1382,6 +1379,19 @@ class LibraryController(
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) {
val category = (adapter.getItem(position) as? LibraryHeaderItem)?.category ?: return
if (!category.isDynamic) {

View File

@ -80,14 +80,6 @@ class LibraryHeaderHolder(val view: View, private val adapter: LibraryCategoryAd
}
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 = ""
else binding.categoryTitle.text = category.name
if (category.sourceId != null) {
@ -115,7 +107,7 @@ class LibraryHeaderHolder(val view: View, private val adapter: LibraryCategoryAd
when {
adapter.mode == SelectableAdapter.Mode.MULTI -> {
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.catProgress.gone()
setSelection()
@ -127,13 +119,13 @@ class LibraryHeaderHolder(val view: View, private val adapter: LibraryCategoryAd
binding.updateButton.gone()
}
LibraryUpdateService.categoryInQueue(category.id) -> {
binding.collapseArrow.visibleIf(!adapter.isSingleCategory && !category.isDynamic)
binding.collapseArrow.visibleIf(!adapter.isSingleCategory)
binding.checkbox.gone()
binding.catProgress.visible()
binding.updateButton.invisible()
}
else -> {
binding.collapseArrow.visibleIf(!adapter.isSingleCategory && !category.isDynamic)
binding.collapseArrow.visibleIf(!adapter.isSingleCategory)
binding.catProgress.gone()
binding.checkbox.gone()
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.preference.PreferencesHelper
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.source.LocalSource
import eu.kanade.tachiyomi.source.SourceManager
@ -581,12 +583,13 @@ class LibraryPresenter(
}
BY_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))))
}
}.flatten()
}.flatten().toMutableList()
val hiddenDynamics = preferences.collapsedDynamicCategories().get()
val headers = tagItems.map { item ->
Category.createCustom(
item.key,
@ -594,11 +597,12 @@ class LibraryPresenter(
preferences.librarySortingAscending().getOrDefault()
).apply {
id = item.value.catId
if (name.contains("◘•◘")) {
val split = name.split("◘•◘")
if (name.contains(sourceSplitter)) {
val split = name.split(sourceSplitter)
name = split.first()
sourceId = split.last().toLongOrNull()
}
isHidden = getDynamicCategoryName(this) in hiddenDynamics
}
}.sortedBy {
if (groupType == BY_TRACK_STATUS) {
@ -607,6 +611,22 @@ class LibraryPresenter(
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 }
return items to headers
}
@ -858,28 +878,61 @@ class LibraryPresenter(
}
fun toggleCategoryVisibility(categoryId: Int) {
if (categories.find { it.id == categoryId }?.isDynamic == true) return
val categoriesHidden = preferences.collapsedCategories().getOrDefault().mapNotNull {
it.toIntOrNull()
}.toMutableSet()
if (categoryId in categoriesHidden) {
categoriesHidden.remove(categoryId)
// if (categories.find { it.id == categoryId }?.isDynamic == true) return
if (groupType == BY_DEFAULT) {
val categoriesHidden = preferences.collapsedCategories().getOrDefault().mapNotNull {
it.toIntOrNull()
}.toMutableSet()
if (categoryId in categoriesHidden) {
categoriesHidden.remove(categoryId)
} else {
categoriesHidden.add(categoryId)
}
preferences.collapsedCategories()
.set(categoriesHidden.map { it.toString() }.toMutableSet())
} else {
categoriesHidden.add(categoryId)
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)
}
preferences.collapsedCategories().set(categoriesHidden.map { it.toString() }.toMutableSet())
getLibrary()
}
private fun getDynamicCategoryName(category: Category): String =
groupType.toString() + dynamicCategorySplitter + (category.sourceId?.toString() ?: category.name)
fun toggleAllCategoryVisibility() {
if (preferences.collapsedCategories().getOrDefault().isEmpty()) {
preferences.collapsedCategories().set(allCategories.map { it.id.toString() }.toMutableSet())
if (groupType == BY_DEFAULT) {
if (allCategoriesExpanded()) {
preferences.collapsedCategories()
.set(allCategories.map { it.id.toString() }.toMutableSet())
} else {
preferences.collapsedCategories().set(mutableSetOf())
}
} else {
preferences.collapsedCategories().set(mutableSetOf())
if (allCategoriesExpanded()) {
preferences.collapsedDynamicCategories() += categories.map { getDynamicCategoryName(it) }
} else {
preferences.collapsedDynamicCategories() -= categories.map { getDynamicCategoryName(it) }
}
}
getLibrary()
}
fun allCategoriesExpanded(): Boolean {
return if (groupType == BY_DEFAULT) {
preferences.collapsedCategories().getOrDefault().isEmpty()
} else {
categories.none { it.isHidden }
}
}
/** download All unread */
fun downloadUnread(mangaList: List<Manga>) {
scope.launch {
@ -925,6 +978,8 @@ class LibraryPresenter(
companion object {
private var lastLibraryItems: List<LibraryItem>? = 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 */
fun updateDB() {

View File

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

View File

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