mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-12-24 00:11:50 +01:00
Option to collapse dynamic categories
This commit is contained in:
parent
94a90c6cec
commit
4bb6dbf528
@ -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())
|
||||||
|
@ -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) {
|
||||||
|
@ -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)
|
||||||
|
@ -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() {
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
|
Loading…
Reference in New Issue
Block a user