mirror of
https://github.com/null2264/yokai.git
synced 2025-06-21 10:44:42 +00:00
Add option to tap on certain stats for a filtered library
For series type, status, source, tracker, and tag; open a subclass of the library to only show the filtered results
This commit is contained in:
parent
46e0eb4233
commit
173fc8b32c
8 changed files with 256 additions and 57 deletions
|
@ -0,0 +1,78 @@
|
||||||
|
package eu.kanade.tachiyomi.ui.library
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
|
import android.view.View
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import eu.kanade.tachiyomi.ui.library.filter.FilterBottomSheet
|
||||||
|
import eu.kanade.tachiyomi.util.view.collapse
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
|
class FilteredLibraryController(bundle: Bundle? = null) : LibraryController(bundle) {
|
||||||
|
|
||||||
|
private var queryText: String? = null
|
||||||
|
var filterDownloaded: Int = 0
|
||||||
|
private set
|
||||||
|
var filterUnread: Int = 0
|
||||||
|
private set
|
||||||
|
var filterStatus: Int? = null
|
||||||
|
private set
|
||||||
|
var filterTracked: Int = 0
|
||||||
|
private set
|
||||||
|
var filterMangaType: Int = 0
|
||||||
|
private set
|
||||||
|
|
||||||
|
private var customTitle: String? = null
|
||||||
|
|
||||||
|
override fun getTitle(): String? {
|
||||||
|
return customTitle ?: super.getTitle()
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
title: String,
|
||||||
|
queryText: String? = null,
|
||||||
|
filterDownloaded: Int = 0,
|
||||||
|
filterUnread: Int = 0,
|
||||||
|
filterStatus: Int? = null,
|
||||||
|
filterTracked: Int = 0,
|
||||||
|
filterTrackerName: String? = null,
|
||||||
|
filterMangaType: Int = 0,
|
||||||
|
) : this() {
|
||||||
|
customTitle = title
|
||||||
|
this.filterDownloaded = filterDownloaded
|
||||||
|
this.filterUnread = filterUnread
|
||||||
|
this.filterStatus = filterStatus
|
||||||
|
this.filterTracked = filterTracked
|
||||||
|
if (filterTracked != 0 && filterTrackerName != null) {
|
||||||
|
FilterBottomSheet.FILTER_TRACKER = filterTrackerName
|
||||||
|
}
|
||||||
|
this.filterMangaType = filterMangaType
|
||||||
|
this.queryText = queryText
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View) {
|
||||||
|
super.onViewCreated(view)
|
||||||
|
binding.filterBottomSheet.root.sheetBehavior?.isHideable = false
|
||||||
|
binding.filterBottomSheet.root.sheetBehavior?.collapse()
|
||||||
|
binding.filterBottomSheet.filterScroll.isVisible = false
|
||||||
|
binding.filterBottomSheet.secondLayout.isVisible = false
|
||||||
|
binding.filterBottomSheet.viewOptions.isVisible = false
|
||||||
|
binding.filterBottomSheet.pill.isVisible = false
|
||||||
|
queryText?.let { search(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showFloatingBar() = false
|
||||||
|
|
||||||
|
override fun handleBack(): Boolean {
|
||||||
|
if (binding.recyclerCover.isClickable) {
|
||||||
|
showCategories(false)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { }
|
||||||
|
override fun toggleCategoryVisibility(position: Int) { }
|
||||||
|
override fun hasActiveFiltersFromPref(): Boolean = false
|
||||||
|
}
|
|
@ -137,7 +137,7 @@ import kotlin.math.roundToInt
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
import kotlin.random.nextInt
|
import kotlin.random.nextInt
|
||||||
|
|
||||||
class LibraryController(
|
open class LibraryController(
|
||||||
bundle: Bundle? = null,
|
bundle: Bundle? = null,
|
||||||
val preferences: PreferencesHelper = Injekt.get(),
|
val preferences: PreferencesHelper = Injekt.get(),
|
||||||
) : BaseCoroutineController<LibraryControllerBinding, LibraryPresenter>(bundle),
|
) : BaseCoroutineController<LibraryControllerBinding, LibraryPresenter>(bundle),
|
||||||
|
@ -181,6 +181,9 @@ class LibraryController(
|
||||||
*/
|
*/
|
||||||
private var query = ""
|
private var query = ""
|
||||||
|
|
||||||
|
val isSubClass: Boolean
|
||||||
|
get() = this is FilteredLibraryController
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Currently selected mangas.
|
* Currently selected mangas.
|
||||||
*/
|
*/
|
||||||
|
@ -235,7 +238,7 @@ class LibraryController(
|
||||||
private lateinit var elevateAppBar: ((Boolean) -> Unit)
|
private lateinit var elevateAppBar: ((Boolean) -> Unit)
|
||||||
private var hopperOffset = 0f
|
private var hopperOffset = 0f
|
||||||
private val maxHopperOffset: Float
|
private val maxHopperOffset: Float
|
||||||
get() = if (activityBinding?.bottomNav != null) {
|
get() = if (activityBinding?.bottomNav != null && !isSubClass) {
|
||||||
55f.dpToPx
|
55f.dpToPx
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
|
@ -301,7 +304,9 @@ class LibraryController(
|
||||||
hopperOffset += dy
|
hopperOffset += dy
|
||||||
hopperOffset = hopperOffset.coerceIn(0f, maxHopperOffset)
|
hopperOffset = hopperOffset.coerceIn(0f, maxHopperOffset)
|
||||||
}
|
}
|
||||||
if (!preferences.hideBottomNavOnScroll().get() || activityBinding?.bottomNav == null) {
|
if (!preferences.hideBottomNavOnScroll().get() || activityBinding?.bottomNav == null ||
|
||||||
|
isSubClass
|
||||||
|
) {
|
||||||
updateFilterSheetY()
|
updateFilterSheetY()
|
||||||
}
|
}
|
||||||
if (!binding.fastScroller.isFastScrolling) {
|
if (!binding.fastScroller.isFastScrolling) {
|
||||||
|
@ -328,7 +333,9 @@ class LibraryController(
|
||||||
val savedCurrentCategory = getHeader(true)?.category ?: return
|
val savedCurrentCategory = getHeader(true)?.category ?: return
|
||||||
if (savedCurrentCategory.order != lastUsedCategory) {
|
if (savedCurrentCategory.order != lastUsedCategory) {
|
||||||
lastUsedCategory = savedCurrentCategory.order
|
lastUsedCategory = savedCurrentCategory.order
|
||||||
preferences.lastUsedCategory().set(savedCurrentCategory.order)
|
if (!isSubClass) {
|
||||||
|
preferences.lastUsedCategory().set(savedCurrentCategory.order)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,7 +370,7 @@ class LibraryController(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateFilterSheetY() {
|
fun updateFilterSheetY() {
|
||||||
val bottomBar = activityBinding?.bottomNav
|
val bottomBar = if (!isSubClass) activityBinding?.bottomNav else null
|
||||||
val systemInsets = view?.rootWindowInsetsCompat?.getInsets(systemBars())
|
val systemInsets = view?.rootWindowInsetsCompat?.getInsets(systemBars())
|
||||||
val bottomSheet = binding.filterBottomSheet.filterBottomSheet
|
val bottomSheet = binding.filterBottomSheet.filterBottomSheet
|
||||||
if (bottomBar != null) {
|
if (bottomBar != null) {
|
||||||
|
@ -393,13 +400,14 @@ class LibraryController(
|
||||||
android.R.integer.config_shortAnimTime,
|
android.R.integer.config_shortAnimTime,
|
||||||
) ?: 0
|
) ?: 0
|
||||||
if (preferences.autohideHopper().get()) {
|
if (preferences.autohideHopper().get()) {
|
||||||
|
val bottomBar = if (isSubClass) null else activityBinding?.bottomNav
|
||||||
// Flow same snap rules as bottom nav
|
// Flow same snap rules as bottom nav
|
||||||
val closerToHopperBottom = hopperOffset > maxHopperOffset / 2
|
val closerToHopperBottom = hopperOffset > maxHopperOffset / 2
|
||||||
val halfWayBottom = activityBinding?.bottomNav?.height?.toFloat()?.div(2) ?: 0f
|
val halfWayBottom = bottomBar?.height?.toFloat()?.div(2) ?: 0f
|
||||||
val closerToBottom = (activityBinding?.bottomNav?.translationY ?: 0f) > halfWayBottom
|
val closerToBottom = (bottomBar?.translationY ?: 0f) > halfWayBottom
|
||||||
val atTop = !binding.libraryGridRecycler.recycler.canScrollVertically(-1)
|
val atTop = !binding.libraryGridRecycler.recycler.canScrollVertically(-1)
|
||||||
val closerToEdge =
|
val closerToEdge =
|
||||||
if (preferences.hideBottomNavOnScroll().get() && activityBinding?.bottomNav != null) {
|
if (preferences.hideBottomNavOnScroll().get() && bottomBar != null) {
|
||||||
closerToBottom && !atTop
|
closerToBottom && !atTop
|
||||||
} else {
|
} else {
|
||||||
closerToHopperBottom
|
closerToHopperBottom
|
||||||
|
@ -529,7 +537,9 @@ class LibraryController(
|
||||||
activity!!.getString(R.string.group_library_by),
|
activity!!.getString(R.string.group_library_by),
|
||||||
presenter.groupType,
|
presenter.groupType,
|
||||||
) { _, item ->
|
) { _, item ->
|
||||||
preferences.groupLibraryBy().set(item)
|
if (!isSubClass) {
|
||||||
|
preferences.groupLibraryBy().set(item)
|
||||||
|
}
|
||||||
presenter.groupType = item
|
presenter.groupType = item
|
||||||
shouldScrollToTop = true
|
shouldScrollToTop = true
|
||||||
presenter.getLibrary()
|
presenter.getLibrary()
|
||||||
|
@ -538,7 +548,7 @@ class LibraryController(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showDisplayOptions() {
|
private fun showDisplayOptions() {
|
||||||
if (displaySheet == null) {
|
if (displaySheet == null && !isSubClass) {
|
||||||
displaySheet = TabbedLibraryDisplaySheet(this)
|
displaySheet = TabbedLibraryDisplaySheet(this)
|
||||||
displaySheet?.show()
|
displaySheet?.show()
|
||||||
}
|
}
|
||||||
|
@ -548,7 +558,9 @@ class LibraryController(
|
||||||
if (filterTooltip != null) {
|
if (filterTooltip != null) {
|
||||||
filterTooltip?.close()
|
filterTooltip?.close()
|
||||||
filterTooltip = null
|
filterTooltip = null
|
||||||
preferences.shownFilterTutorial().set(true)
|
if (!isSubClass) {
|
||||||
|
preferences.shownFilterTutorial().set(true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -623,7 +635,7 @@ class LibraryController(
|
||||||
createActionModeIfNeeded()
|
createActionModeIfNeeded()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (presenter.libraryItems.isNotEmpty()) {
|
if (presenter.libraryItems.isNotEmpty() && !isSubClass) {
|
||||||
presenter.restoreLibrary()
|
presenter.restoreLibrary()
|
||||||
if (justStarted) {
|
if (justStarted) {
|
||||||
val activityBinding = activityBinding ?: return
|
val activityBinding = activityBinding ?: return
|
||||||
|
@ -800,15 +812,16 @@ class LibraryController(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateHopperY(windowInsets: WindowInsetsCompat? = null) {
|
open fun updateHopperY(windowInsets: WindowInsetsCompat? = null) {
|
||||||
val view = view ?: return
|
val view = view ?: return
|
||||||
val insets = windowInsets ?: view.rootWindowInsetsCompat
|
val insets = windowInsets ?: view.rootWindowInsetsCompat
|
||||||
|
val bottomNav = if (isSubClass) null else activityBinding?.bottomNav
|
||||||
val listOfYs = mutableListOf(
|
val listOfYs = mutableListOf(
|
||||||
binding.filterBottomSheet.filterBottomSheet.y,
|
binding.filterBottomSheet.filterBottomSheet.y,
|
||||||
activityBinding?.bottomNav?.y ?: binding.filterBottomSheet.filterBottomSheet.y,
|
bottomNav?.y ?: binding.filterBottomSheet.filterBottomSheet.y,
|
||||||
)
|
)
|
||||||
val insetBottom = insets?.getInsets(systemBars())?.bottom ?: 0
|
val insetBottom = insets?.getInsets(systemBars())?.bottom ?: 0
|
||||||
if (!preferences.autohideHopper().get() || activityBinding?.bottomNav == null) {
|
if (!preferences.autohideHopper().get() || bottomNav == null) {
|
||||||
listOfYs.add(view.height - (insetBottom).toFloat())
|
listOfYs.add(view.height - (insetBottom).toFloat())
|
||||||
}
|
}
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && insets?.isImeVisible() == true) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && insets?.isImeVisible() == true) {
|
||||||
|
@ -819,9 +832,14 @@ class LibraryController(
|
||||||
(listOfYs.minOrNull() ?: binding.filterBottomSheet.filterBottomSheet.y) +
|
(listOfYs.minOrNull() ?: binding.filterBottomSheet.filterBottomSheet.y) +
|
||||||
hopperOffset +
|
hopperOffset +
|
||||||
binding.libraryGridRecycler.recycler.translationY
|
binding.libraryGridRecycler.recycler.translationY
|
||||||
if (view.height - insetBottom < binding.categoryHopperFrame.y) {
|
val bottom = if (isSubClass) {
|
||||||
|
binding.filterBottomSheet.root.height + binding.jumperCategoryText.height + 12.dpToPx
|
||||||
|
} else {
|
||||||
|
insetBottom
|
||||||
|
}
|
||||||
|
if (view.height - bottom < binding.categoryHopperFrame.y) {
|
||||||
binding.jumperCategoryText.translationY =
|
binding.jumperCategoryText.translationY =
|
||||||
-(binding.categoryHopperFrame.y - (view.height - insetBottom)) +
|
-(binding.categoryHopperFrame.y - (view.height - bottom)) +
|
||||||
binding.libraryGridRecycler.recycler.translationY
|
binding.libraryGridRecycler.recycler.translationY
|
||||||
} else {
|
} else {
|
||||||
binding.jumperCategoryText.translationY = binding.libraryGridRecycler.recycler.translationY
|
binding.jumperCategoryText.translationY = binding.libraryGridRecycler.recycler.translationY
|
||||||
|
@ -945,9 +963,10 @@ class LibraryController(
|
||||||
|
|
||||||
private fun setRecyclerLayout() {
|
private fun setRecyclerLayout() {
|
||||||
with(binding.libraryGridRecycler.recycler) {
|
with(binding.libraryGridRecycler.recycler) {
|
||||||
|
val bottomNav = if (isSubClass) null else activityBinding?.bottomNav
|
||||||
viewScope.launchUI {
|
viewScope.launchUI {
|
||||||
updatePaddingRelative(
|
updatePaddingRelative(
|
||||||
bottom = 50.dpToPx + (activityBinding?.bottomNav?.height ?: 0),
|
bottom = 50.dpToPx + (bottomNav?.height ?: 0),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
useStaggered(preferences)
|
useStaggered(preferences)
|
||||||
|
@ -1110,7 +1129,7 @@ class LibraryController(
|
||||||
if (binding.recyclerLayout.alpha == 0f) {
|
if (binding.recyclerLayout.alpha == 0f) {
|
||||||
binding.recyclerLayout.animate().alpha(1f).setDuration(500).start()
|
binding.recyclerLayout.animate().alpha(1f).setDuration(500).start()
|
||||||
}
|
}
|
||||||
if (justStarted && freshStart) {
|
if (justStarted && freshStart && !isSubClass) {
|
||||||
val activeC = activeCategory
|
val activeC = activeCategory
|
||||||
scrollToHeader(activeCategory)
|
scrollToHeader(activeCategory)
|
||||||
binding.libraryGridRecycler.recycler.post {
|
binding.libraryGridRecycler.recycler.post {
|
||||||
|
@ -1238,7 +1257,7 @@ class LibraryController(
|
||||||
.setDuration(duration)
|
.setDuration(duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showCategories(show: Boolean, closeSearch: Boolean = false, category: Int = -1) {
|
internal fun showCategories(show: Boolean, closeSearch: Boolean = false, category: Int = -1) {
|
||||||
binding.recyclerCover.isClickable = show
|
binding.recyclerCover.isClickable = show
|
||||||
binding.recyclerCover.isFocusable = show
|
binding.recyclerCover.isFocusable = show
|
||||||
(activity as? MainActivity)?.apply {
|
(activity as? MainActivity)?.apply {
|
||||||
|
@ -1326,7 +1345,9 @@ class LibraryController(
|
||||||
saveActiveCategory(it)
|
saveActiveCategory(it)
|
||||||
}
|
}
|
||||||
activeCategory = pos
|
activeCategory = pos
|
||||||
preferences.lastUsedCategory().set(pos)
|
if (!isSubClass) {
|
||||||
|
preferences.lastUsedCategory().set(pos)
|
||||||
|
}
|
||||||
binding.libraryGridRecycler.recycler.post {
|
binding.libraryGridRecycler.recycler.post {
|
||||||
if (isControllerVisible) {
|
if (isControllerVisible) {
|
||||||
activityBinding.appBar.y = 0f
|
activityBinding.appBar.y = 0f
|
||||||
|
@ -1364,7 +1385,10 @@ class LibraryController(
|
||||||
presenter.forceShowAllCategories = preferences.showAllCategoriesWhenSearchingSingleCategory().get()
|
presenter.forceShowAllCategories = preferences.showAllCategoriesWhenSearchingSingleCategory().get()
|
||||||
presenter.getLibrary()
|
presenter.getLibrary()
|
||||||
} else if (query.isNullOrBlank() && this.query.isNotBlank() && !isShowAllCategoriesSet) {
|
} else if (query.isNullOrBlank() && this.query.isNotBlank() && !isShowAllCategoriesSet) {
|
||||||
preferences.showAllCategoriesWhenSearchingSingleCategory().set(presenter.forceShowAllCategories)
|
if (!isSubClass) {
|
||||||
|
preferences.showAllCategoriesWhenSearchingSingleCategory()
|
||||||
|
.set(presenter.forceShowAllCategories)
|
||||||
|
}
|
||||||
presenter.forceShowAllCategories = false
|
presenter.forceShowAllCategories = false
|
||||||
presenter.getLibrary()
|
presenter.getLibrary()
|
||||||
}
|
}
|
||||||
|
@ -2121,4 +2145,13 @@ class LibraryController(
|
||||||
destroyActionModeIfNeeded()
|
destroyActionModeIfNeeded()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open fun hasActiveFiltersFromPref(): Boolean {
|
||||||
|
return preferences.filterDownloaded().get() > 0 ||
|
||||||
|
preferences.filterUnread().get() > 0 ||
|
||||||
|
preferences.filterCompleted().get() > 0 ||
|
||||||
|
preferences.filterTracked().get() > 0 ||
|
||||||
|
preferences.filterMangaType().get() > 0 ||
|
||||||
|
FilterBottomSheet.FILTER_TRACKER.isNotEmpty()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -196,7 +196,7 @@ class LibraryHeaderHolder(val view: View, val adapter: LibraryCategoryAdapter) :
|
||||||
binding.updateButton.isVisible = false
|
binding.updateButton.isVisible = false
|
||||||
setSelection()
|
setSelection()
|
||||||
}
|
}
|
||||||
(category.id ?: -1) < 0 -> {
|
(category.id ?: -1) < 0 || adapter.libraryListener is FilteredLibraryController -> {
|
||||||
binding.collapseArrow.isVisible = false
|
binding.collapseArrow.isVisible = false
|
||||||
binding.checkbox.isVisible = false
|
binding.checkbox.isVisible = false
|
||||||
setRefreshing(false)
|
setRefreshing(false)
|
||||||
|
|
|
@ -103,6 +103,9 @@ class LibraryPresenter(
|
||||||
private val libraryIsGrouped
|
private val libraryIsGrouped
|
||||||
get() = groupType != UNGROUPED
|
get() = groupType != UNGROUPED
|
||||||
|
|
||||||
|
private val controllerIsSubClass
|
||||||
|
get() = controller?.isSubClass == true
|
||||||
|
|
||||||
var hasActiveFilters: Boolean = run {
|
var hasActiveFilters: Boolean = run {
|
||||||
val filterDownloaded = preferences.filterDownloaded().get()
|
val filterDownloaded = preferences.filterDownloaded().get()
|
||||||
|
|
||||||
|
@ -119,17 +122,22 @@ class LibraryPresenter(
|
||||||
|
|
||||||
/** Save the current list to speed up loading later */
|
/** Save the current list to speed up loading later */
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
|
val isSubController = controllerIsSubClass
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
lastLibraryItems = libraryItems
|
if (!isSubController) {
|
||||||
lastCategories = categories
|
lastLibraryItems = libraryItems
|
||||||
|
lastCategories = categories
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
lastLibraryItems?.let { libraryItems = it }
|
if (!controllerIsSubClass) {
|
||||||
lastCategories?.let { categories = it }
|
lastLibraryItems?.let { libraryItems = it }
|
||||||
lastCategories = null
|
lastCategories?.let { categories = it }
|
||||||
lastLibraryItems = null
|
lastCategories = null
|
||||||
|
lastLibraryItems = null
|
||||||
|
}
|
||||||
getLibrary()
|
getLibrary()
|
||||||
if (preferences.showLibrarySearchSuggestions().isNotSet()) {
|
if (preferences.showLibrarySearchSuggestions().isNotSet()) {
|
||||||
DelayedLibrarySuggestionsJob.setupTask(context, true)
|
DelayedLibrarySuggestionsJob.setupTask(context, true)
|
||||||
|
@ -261,15 +269,16 @@ class LibraryPresenter(
|
||||||
* @param items the items to filter.
|
* @param items the items to filter.
|
||||||
*/
|
*/
|
||||||
private fun applyFilters(items: List<LibraryItem>): List<LibraryItem> {
|
private fun applyFilters(items: List<LibraryItem>): List<LibraryItem> {
|
||||||
val filterDownloaded = preferences.filterDownloaded().get()
|
val customFilters = controller as? FilteredLibraryController
|
||||||
|
val filterDownloaded = customFilters?.filterDownloaded ?: preferences.filterDownloaded().get()
|
||||||
|
|
||||||
val filterUnread = preferences.filterUnread().get()
|
val filterUnread = customFilters?.filterUnread ?: preferences.filterUnread().get()
|
||||||
|
|
||||||
val filterCompleted = preferences.filterCompleted().get()
|
val filterCompleted = preferences.filterCompleted().get()
|
||||||
|
|
||||||
val filterTracked = preferences.filterTracked().get()
|
val filterTracked = customFilters?.filterTracked ?: preferences.filterTracked().get()
|
||||||
|
|
||||||
val filterMangaType = preferences.filterMangaType().get()
|
val filterMangaType = customFilters?.filterMangaType ?: preferences.filterMangaType().get()
|
||||||
|
|
||||||
val showEmptyCategoriesWhileFiltering = preferences.showEmptyCategoriesWhileFiltering().get()
|
val showEmptyCategoriesWhileFiltering = preferences.showEmptyCategoriesWhileFiltering().get()
|
||||||
|
|
||||||
|
@ -295,6 +304,7 @@ class LibraryPresenter(
|
||||||
filterTracked,
|
filterTracked,
|
||||||
filterMangaType,
|
filterMangaType,
|
||||||
filterTrackers,
|
filterTrackers,
|
||||||
|
customFilters?.filterStatus,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -314,6 +324,7 @@ class LibraryPresenter(
|
||||||
filterTracked,
|
filterTracked,
|
||||||
filterMangaType,
|
filterMangaType,
|
||||||
filterTrackers,
|
filterTrackers,
|
||||||
|
customFilters?.filterStatus,
|
||||||
)
|
)
|
||||||
if (matches) {
|
if (matches) {
|
||||||
missingCategorySet.remove(item.manga.category)
|
missingCategorySet.remove(item.manga.category)
|
||||||
|
@ -336,6 +347,7 @@ class LibraryPresenter(
|
||||||
filterTracked: Int,
|
filterTracked: Int,
|
||||||
filterMangaType: Int,
|
filterMangaType: Int,
|
||||||
filterTrackers: String,
|
filterTrackers: String,
|
||||||
|
filterStatus: Int? = null,
|
||||||
): Boolean {
|
): Boolean {
|
||||||
if (filterUnread == STATE_INCLUDE && item.manga.unread == 0) return false
|
if (filterUnread == STATE_INCLUDE && item.manga.unread == 0) return false
|
||||||
if (filterUnread == STATE_EXCLUDE && item.manga.unread > 0) return false
|
if (filterUnread == STATE_EXCLUDE && item.manga.unread > 0) return false
|
||||||
|
@ -355,9 +367,13 @@ class LibraryPresenter(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter for completed status of manga
|
if (filterStatus != null) {
|
||||||
if (filterCompleted == STATE_INCLUDE && item.manga.status != SManga.COMPLETED) return false
|
if (filterStatus != item.manga.status) return false
|
||||||
if (filterCompleted == STATE_EXCLUDE && item.manga.status == SManga.COMPLETED) return false
|
} else {
|
||||||
|
// Filter for completed status of manga
|
||||||
|
if (filterCompleted == STATE_INCLUDE && item.manga.status != SManga.COMPLETED) return false
|
||||||
|
if (filterCompleted == STATE_EXCLUDE && item.manga.status == SManga.COMPLETED) return false
|
||||||
|
}
|
||||||
|
|
||||||
// Filter for tracked (or per tracked service)
|
// Filter for tracked (or per tracked service)
|
||||||
if (filterTracked != STATE_IGNORE) {
|
if (filterTracked != STATE_IGNORE) {
|
||||||
|
@ -615,7 +631,7 @@ class LibraryPresenter(
|
||||||
LibraryItem(it, headerItem, viewContext)
|
LibraryItem(it, headerItem, viewContext)
|
||||||
}.toMutableList()
|
}.toMutableList()
|
||||||
|
|
||||||
val categoriesHidden = if (forceShowAllCategories) {
|
val categoriesHidden = if (forceShowAllCategories || controllerIsSubClass) {
|
||||||
emptySet()
|
emptySet()
|
||||||
} else {
|
} else {
|
||||||
preferences.collapsedCategories().get().mapNotNull { it.toIntOrNull() }.toSet()
|
preferences.collapsedCategories().get().mapNotNull { it.toIntOrNull() }.toSet()
|
||||||
|
@ -786,7 +802,11 @@ class LibraryPresenter(
|
||||||
}
|
}
|
||||||
}.flatten().toMutableList()
|
}.flatten().toMutableList()
|
||||||
|
|
||||||
val hiddenDynamics = preferences.collapsedDynamicCategories().get()
|
val hiddenDynamics = if (controllerIsSubClass) {
|
||||||
|
emptySet()
|
||||||
|
} else {
|
||||||
|
preferences.collapsedDynamicCategories().get()
|
||||||
|
}
|
||||||
var headers = tagItems.map { item ->
|
var headers = tagItems.map { item ->
|
||||||
Category.createCustom(
|
Category.createCustom(
|
||||||
item.key,
|
item.key,
|
||||||
|
|
|
@ -147,7 +147,7 @@ class FilterBottomSheet @JvmOverloads constructor(context: Context, attrs: Attri
|
||||||
|
|
||||||
sheetBehavior?.isGestureInsetBottomIgnored = true
|
sheetBehavior?.isGestureInsetBottomIgnored = true
|
||||||
|
|
||||||
val activeFilters = hasActiveFiltersFromPref()
|
val activeFilters = hasActiveFiltersFromPref() && !controller.isSubClass
|
||||||
if (activeFilters && sheetBehavior.isHidden() && sheetBehavior?.skipCollapsed == false) {
|
if (activeFilters && sheetBehavior.isHidden() && sheetBehavior?.skipCollapsed == false) {
|
||||||
sheetBehavior?.collapse()
|
sheetBehavior?.collapse()
|
||||||
controller.viewScope.launchUI {
|
controller.viewScope.launchUI {
|
||||||
|
@ -415,7 +415,7 @@ class FilterBottomSheet @JvmOverloads constructor(context: Context, attrs: Attri
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFilterClicked(view: FilterTagGroup, index: Int, updatePreference: Boolean) {
|
override fun onFilterClicked(view: FilterTagGroup, index: Int, updatePreference: Boolean) {
|
||||||
if (updatePreference) {
|
if (updatePreference && controller?.isSubClass != true) {
|
||||||
when (view) {
|
when (view) {
|
||||||
trackers -> {
|
trackers -> {
|
||||||
FILTER_TRACKER = view.nameOf(index) ?: ""
|
FILTER_TRACKER = view.nameOf(index) ?: ""
|
||||||
|
@ -523,7 +523,6 @@ class FilterBottomSheet @JvmOverloads constructor(context: Context, attrs: Attri
|
||||||
const val STATE_EXCLUDE = 2
|
const val STATE_EXCLUDE = 2
|
||||||
|
|
||||||
var FILTER_TRACKER = ""
|
var FILTER_TRACKER = ""
|
||||||
private set
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Filters(val value: Char, @StringRes val stringRes: Int) {
|
enum class Filters(val value: Char, @StringRes val stringRes: Int) {
|
||||||
|
|
|
@ -52,7 +52,7 @@ class StatsDetailsAdapter(
|
||||||
|
|
||||||
override fun getItemId(position: Int): Long {
|
override fun getItemId(position: Int): Long {
|
||||||
return when (stat) {
|
return when (stat) {
|
||||||
Stats.READ_DURATION -> list[position].mangaId
|
Stats.READ_DURATION -> list[position].id
|
||||||
else -> list[position].label?.hashCode()?.toLong()
|
else -> list[position].label?.hashCode()?.toLong()
|
||||||
} ?: 0L
|
} ?: 0L
|
||||||
}
|
}
|
||||||
|
@ -64,12 +64,18 @@ class StatsDetailsAdapter(
|
||||||
Stats.READ_DURATION -> handleDurationLayout(holder, position)
|
Stats.READ_DURATION -> handleDurationLayout(holder, position)
|
||||||
else -> handleLayout(holder, position)
|
else -> handleLayout(holder, position)
|
||||||
}
|
}
|
||||||
list[position].mangaId?.let { mangaId ->
|
holder.itemView.setOnClickListener {
|
||||||
holder.itemView.setOnClickListener {
|
val item = list[position]
|
||||||
listener?.onItemClicked(mangaId)
|
listener?.onItemClicked(item.id, item.casedLabel ?: item.label)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
holder.itemView.isClickable = list[position].mangaId != null
|
holder.itemView.isClickable = stat in arrayOf(
|
||||||
|
Stats.SERIES_TYPE,
|
||||||
|
Stats.STATUS,
|
||||||
|
Stats.READ_DURATION,
|
||||||
|
Stats.SOURCE,
|
||||||
|
Stats.TRACKER,
|
||||||
|
Stats.TAG,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemCount(): Int {
|
override fun getItemCount(): Int {
|
||||||
|
@ -231,7 +237,7 @@ class StatsDetailsAdapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun interface OnItemClickedListener {
|
fun interface OnItemClickedListener {
|
||||||
fun onItemClicked(mangaId: Long)
|
fun onItemClicked(id: Long?, label: String?)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemViewType(position: Int): Int {
|
override fun getItemViewType(position: Int): Int {
|
||||||
|
|
|
@ -32,6 +32,8 @@ import eu.kanade.tachiyomi.databinding.StatsDetailsChartBinding
|
||||||
import eu.kanade.tachiyomi.databinding.StatsDetailsControllerBinding
|
import eu.kanade.tachiyomi.databinding.StatsDetailsControllerBinding
|
||||||
import eu.kanade.tachiyomi.ui.base.SmallToolbarInterface
|
import eu.kanade.tachiyomi.ui.base.SmallToolbarInterface
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.BaseCoroutineController
|
import eu.kanade.tachiyomi.ui.base.controller.BaseCoroutineController
|
||||||
|
import eu.kanade.tachiyomi.ui.library.FilteredLibraryController
|
||||||
|
import eu.kanade.tachiyomi.ui.library.filter.FilterBottomSheet
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
|
import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
|
||||||
import eu.kanade.tachiyomi.ui.more.stats.StatsHelper.getReadDuration
|
import eu.kanade.tachiyomi.ui.more.stats.StatsHelper.getReadDuration
|
||||||
import eu.kanade.tachiyomi.ui.more.stats.details.StatsDetailsPresenter.Stats
|
import eu.kanade.tachiyomi.ui.more.stats.details.StatsDetailsPresenter.Stats
|
||||||
|
@ -580,9 +582,7 @@ class StatsDetailsController :
|
||||||
concatAdapter.addAdapter(0, headAdapter)
|
concatAdapter.addAdapter(0, headAdapter)
|
||||||
}
|
}
|
||||||
binding.statsRecyclerView.adapter = concatAdapter
|
binding.statsRecyclerView.adapter = concatAdapter
|
||||||
statsAdapter.listener = StatsDetailsAdapter.OnItemClickedListener { mangaId ->
|
statsAdapter.listener = StatsDetailsAdapter.OnItemClickedListener(::onItemClicked)
|
||||||
router.pushController(MangaDetailsController(mangaId).withFadeTransaction())
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
updateStatsAdapter(onlyUpdateDetails)
|
updateStatsAdapter(onlyUpdateDetails)
|
||||||
concatAdapter?.notifyDataSetChanged()
|
concatAdapter?.notifyDataSetChanged()
|
||||||
|
@ -590,6 +590,58 @@ class StatsDetailsController :
|
||||||
if (query.isNotBlank()) statsAdapter?.filter(query)
|
if (query.isNotBlank()) statsAdapter?.filter(query)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onItemClicked(id: Long?, name: String?) {
|
||||||
|
name ?: return
|
||||||
|
when (presenter.selectedStat) {
|
||||||
|
Stats.SERIES_TYPE -> {
|
||||||
|
val seriesType = presenter.seriesTypeStats.indexOf(name) + 1
|
||||||
|
if (seriesType > 0) {
|
||||||
|
router.pushController(
|
||||||
|
FilteredLibraryController(name, filterMangaType = seriesType)
|
||||||
|
.withFadeTransaction(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Stats.STATUS -> {
|
||||||
|
val status = presenter.statusStats.indexOf(name) + 1
|
||||||
|
router.pushController(
|
||||||
|
FilteredLibraryController(name, filterStatus = status)
|
||||||
|
.withFadeTransaction(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Stats.SOURCE, Stats.TAG -> {
|
||||||
|
router.pushController(
|
||||||
|
FilteredLibraryController(name, queryText = name).withFadeTransaction(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Stats.TRACKER -> {
|
||||||
|
if (id != null) {
|
||||||
|
val loggedServices = presenter.trackManager.services.filter { it.isLogged }
|
||||||
|
val service = loggedServices.find { it.id == id.toInt() } ?: return
|
||||||
|
val serviceName = binding.root.context.getString(service.nameRes())
|
||||||
|
router.pushController(
|
||||||
|
FilteredLibraryController(
|
||||||
|
serviceName,
|
||||||
|
filterTracked = FilterBottomSheet.STATE_INCLUDE,
|
||||||
|
filterTrackerName = serviceName,
|
||||||
|
).withFadeTransaction(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
router.pushController(
|
||||||
|
FilteredLibraryController(
|
||||||
|
name,
|
||||||
|
filterTracked = FilterBottomSheet.STATE_EXCLUDE,
|
||||||
|
).withFadeTransaction(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Stats.READ_DURATION -> id?.let {
|
||||||
|
router.pushController(MangaDetailsController(id).withFadeTransaction())
|
||||||
|
}
|
||||||
|
else -> return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun updateStatsAdapter(onlyUpdateDetails: Boolean) {
|
private fun updateStatsAdapter(onlyUpdateDetails: Boolean) {
|
||||||
val oldCount = statsAdapter?.list?.size ?: 0
|
val oldCount = statsAdapter?.list?.size ?: 0
|
||||||
statsAdapter?.stat = presenter.selectedStat!!
|
statsAdapter?.stat = presenter.selectedStat!!
|
||||||
|
|
|
@ -36,7 +36,7 @@ import kotlin.math.roundToInt
|
||||||
class StatsDetailsPresenter(
|
class StatsDetailsPresenter(
|
||||||
private val db: DatabaseHelper = Injekt.get(),
|
private val db: DatabaseHelper = Injekt.get(),
|
||||||
prefs: PreferencesHelper = Injekt.get(),
|
prefs: PreferencesHelper = Injekt.get(),
|
||||||
private val trackManager: TrackManager = Injekt.get(),
|
val trackManager: TrackManager = Injekt.get(),
|
||||||
private val sourceManager: SourceManager = Injekt.get(),
|
private val sourceManager: SourceManager = Injekt.get(),
|
||||||
) : BaseCoroutinePresenter<StatsDetailsController>() {
|
) : BaseCoroutinePresenter<StatsDetailsController>() {
|
||||||
|
|
||||||
|
@ -141,6 +141,7 @@ class StatsDetailsPresenter(
|
||||||
totalChapters = mangaList.sumOf { it.totalChapters },
|
totalChapters = mangaList.sumOf { it.totalChapters },
|
||||||
label = context.mapSeriesType(seriesType).uppercase(),
|
label = context.mapSeriesType(seriesType).uppercase(),
|
||||||
readDuration = mangaList.getReadDuration(),
|
readDuration = mangaList.getReadDuration(),
|
||||||
|
casedLabel = context.mapSeriesType(seriesType),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -161,6 +162,7 @@ class StatsDetailsPresenter(
|
||||||
totalChapters = mangaList.sumOf { it.totalChapters },
|
totalChapters = mangaList.sumOf { it.totalChapters },
|
||||||
label = context.mapStatus(status).uppercase(),
|
label = context.mapStatus(status).uppercase(),
|
||||||
readDuration = mangaList.getReadDuration(),
|
readDuration = mangaList.getReadDuration(),
|
||||||
|
casedLabel = context.mapStatus(status),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -256,6 +258,8 @@ class StatsDetailsPresenter(
|
||||||
iconRes = service?.getLogo(),
|
iconRes = service?.getLogo(),
|
||||||
iconBGColor = service?.getLogoColor(),
|
iconBGColor = service?.getLogoColor(),
|
||||||
readDuration = mangaAndTrack.map { it.first }.getReadDuration(),
|
readDuration = mangaAndTrack.map { it.first }.getReadDuration(),
|
||||||
|
id = service?.id?.toLong(),
|
||||||
|
casedLabel = label,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -279,6 +283,7 @@ class StatsDetailsPresenter(
|
||||||
label = sourceName.uppercase(),
|
label = sourceName.uppercase(),
|
||||||
icon = source?.icon(),
|
icon = source?.icon(),
|
||||||
readDuration = mangaList.getReadDuration(),
|
readDuration = mangaList.getReadDuration(),
|
||||||
|
casedLabel = source?.name,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -310,8 +315,12 @@ class StatsDetailsPresenter(
|
||||||
private fun setupTags() {
|
private fun setupTags() {
|
||||||
currentStats = ArrayList()
|
currentStats = ArrayList()
|
||||||
val mangaFiltered = mangasDistinct.filterByChip()
|
val mangaFiltered = mangasDistinct.filterByChip()
|
||||||
val tags = mangaFiltered.flatMap { it.getTags() }.distinct()
|
val tags = mangaFiltered.flatMap { it.getTags() }.distinctBy { it.uppercase() }
|
||||||
val libraryFormat = tags.map { tag -> tag to mangaFiltered.filter { tag in it.getTags() } }
|
val libraryFormat = tags.map { tag ->
|
||||||
|
tag to mangaFiltered.filter {
|
||||||
|
it.getTags().any { mangaTag -> mangaTag.equals(tag, true) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
libraryFormat.forEach { (tag, mangaList) ->
|
libraryFormat.forEach { (tag, mangaList) ->
|
||||||
currentStats?.add(
|
currentStats?.add(
|
||||||
|
@ -323,6 +332,7 @@ class StatsDetailsPresenter(
|
||||||
totalChapters = mangaList.sumOf { it.totalChapters },
|
totalChapters = mangaList.sumOf { it.totalChapters },
|
||||||
label = tag.uppercase(),
|
label = tag.uppercase(),
|
||||||
readDuration = mangaList.getReadDuration(),
|
readDuration = mangaList.getReadDuration(),
|
||||||
|
casedLabel = tag,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -370,7 +380,7 @@ class StatsDetailsPresenter(
|
||||||
label = manga.title,
|
label = manga.title,
|
||||||
subLabel = sources.find { it.id == manga.source }?.toString(),
|
subLabel = sources.find { it.id == manga.source }?.toString(),
|
||||||
readDuration = history.sumOf { it.time_read },
|
readDuration = history.sumOf { it.time_read },
|
||||||
mangaId = manga.id,
|
id = manga.id,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -457,7 +467,7 @@ class StatsDetailsPresenter(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Manga.getTags(): List<String> {
|
private fun Manga.getTags(): List<String> {
|
||||||
return getGenres()?.map { it.uppercase() } ?: emptyList()
|
return getGenres() ?: emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -669,6 +679,7 @@ class StatsDetailsPresenter(
|
||||||
var icon: Drawable? = null,
|
var icon: Drawable? = null,
|
||||||
var subLabel: String? = null,
|
var subLabel: String? = null,
|
||||||
var readDuration: Long = 0,
|
var readDuration: Long = 0,
|
||||||
var mangaId: Long? = null,
|
var id: Long? = null,
|
||||||
|
var casedLabel: String? = null,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue