ChaptersSettingsSheet: Single source of truth and use new manga class (#7342)

Currently breaks initial settings state until the source of truth is
properly updated.

(cherry picked from commit 005b9b595cfe41484eea94998d2f3c9918759a94)

# Conflicts:
#	app/src/main/java/eu/kanade/domain/manga/model/Manga.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersSettingsSheet.kt
This commit is contained in:
Ivan Iskandar 2022-06-19 23:29:49 +07:00 committed by Jobobby04
parent 3f94fd8e6e
commit 29f992fe33
3 changed files with 183 additions and 51 deletions

View File

@ -2,8 +2,10 @@ package eu.kanade.domain.manga.model
import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.cache.CoverCache
import eu.kanade.tachiyomi.data.library.CustomMangaManager import eu.kanade.tachiyomi.data.library.CustomMangaManager
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.source.LocalSource import eu.kanade.tachiyomi.source.LocalSource
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.widget.ExtendedNavigationView
import tachiyomi.source.model.MangaInfo import tachiyomi.source.model.MangaInfo
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
@ -76,15 +78,85 @@ data class Manga(
} }
} }
companion object { val displayMode: Long
get() = chapterFlags and CHAPTER_DISPLAY_MASK
val unreadFilterRaw: Long
get() = chapterFlags and CHAPTER_UNREAD_MASK
val downloadedFilterRaw: Long
get() = chapterFlags and CHAPTER_DOWNLOADED_MASK
val bookmarkedFilterRaw: Long
get() = chapterFlags and CHAPTER_BOOKMARKED_MASK
val unreadFilter: TriStateFilter
get() = when (unreadFilterRaw) {
CHAPTER_SHOW_UNREAD -> TriStateFilter.ENABLED_IS
CHAPTER_SHOW_READ -> TriStateFilter.ENABLED_NOT
else -> TriStateFilter.DISABLED
}
val downloadedFilter: TriStateFilter
get() {
if (forceDownloaded()) return TriStateFilter.ENABLED_IS
return when (downloadedFilterRaw) {
CHAPTER_SHOW_DOWNLOADED -> TriStateFilter.ENABLED_IS
CHAPTER_SHOW_NOT_DOWNLOADED -> TriStateFilter.ENABLED_NOT
else -> TriStateFilter.DISABLED
}
}
val bookmarkedFilter: TriStateFilter
get() = when (bookmarkedFilterRaw) {
CHAPTER_SHOW_BOOKMARKED -> TriStateFilter.ENABLED_IS
CHAPTER_SHOW_NOT_BOOKMARKED -> TriStateFilter.ENABLED_NOT
else -> TriStateFilter.DISABLED
}
fun chaptersFiltered(): Boolean {
return unreadFilter != TriStateFilter.DISABLED ||
downloadedFilter != TriStateFilter.DISABLED ||
bookmarkedFilter != TriStateFilter.DISABLED
}
fun forceDownloaded(): Boolean {
return favorite && Injekt.get<PreferencesHelper>().downloadedOnly().get()
}
fun sortDescending(): Boolean {
return chapterFlags and CHAPTER_SORT_DIR_MASK == CHAPTER_SORTING_DESC
}
companion object {
// Generic filter that does not filter anything // Generic filter that does not filter anything
const val SHOW_ALL = 0x00000000L const val SHOW_ALL = 0x00000000L
const val CHAPTER_SORT_DESC = 0x00000000L
const val CHAPTER_SORT_ASC = 0x00000001L
const val CHAPTER_SORT_DIR_MASK = 0x00000001L
const val CHAPTER_SHOW_UNREAD = 0x00000002L
const val CHAPTER_SHOW_READ = 0x00000004L
const val CHAPTER_UNREAD_MASK = 0x00000006L
const val CHAPTER_SHOW_DOWNLOADED = 0x00000008L
const val CHAPTER_SHOW_NOT_DOWNLOADED = 0x00000010L
const val CHAPTER_DOWNLOADED_MASK = 0x00000018L
const val CHAPTER_SHOW_BOOKMARKED = 0x00000020L
const val CHAPTER_SHOW_NOT_BOOKMARKED = 0x00000040L
const val CHAPTER_BOOKMARKED_MASK = 0x00000060L
const val CHAPTER_SORTING_SOURCE = 0x00000000L const val CHAPTER_SORTING_SOURCE = 0x00000000L
const val CHAPTER_SORTING_NUMBER = 0x00000100L const val CHAPTER_SORTING_NUMBER = 0x00000100L
const val CHAPTER_SORTING_UPLOAD_DATE = 0x00000200L const val CHAPTER_SORTING_UPLOAD_DATE = 0x00000200L
const val CHAPTER_SORTING_MASK = 0x00000300L const val CHAPTER_SORTING_MASK = 0x00000300L
const val CHAPTER_SORTING_DESC = 0x00000000L
const val CHAPTER_DISPLAY_NAME = 0x00000000L
const val CHAPTER_DISPLAY_NUMBER = 0x00100000L
const val CHAPTER_DISPLAY_MASK = 0x00100000L
// SY --> // SY -->
private val customMangaManager: CustomMangaManager by injectLazy() private val customMangaManager: CustomMangaManager by injectLazy()
@ -92,6 +164,20 @@ data class Manga(
} }
} }
enum class TriStateFilter {
DISABLED, // Disable filter
ENABLED_IS, // Enabled with "is" filter
ENABLED_NOT, // Enabled with "not" filter
}
fun TriStateFilter.toTriStateGroupState(): ExtendedNavigationView.Item.TriStateGroup.State {
return when (this) {
TriStateFilter.DISABLED -> ExtendedNavigationView.Item.TriStateGroup.State.IGNORE
TriStateFilter.ENABLED_IS -> ExtendedNavigationView.Item.TriStateGroup.State.INCLUDE
TriStateFilter.ENABLED_NOT -> ExtendedNavigationView.Item.TriStateGroup.State.EXCLUDE
}
}
// TODO: Remove when all deps are migrated // TODO: Remove when all deps are migrated
fun Manga.toDbManga(): DbManga = DbManga.create(url, ogTitle, source).also { fun Manga.toDbManga(): DbManga = DbManga.create(url, ogTitle, source).also {
it.id = id it.id = id
@ -101,6 +187,7 @@ fun Manga.toDbManga(): DbManga = DbManga.create(url, ogTitle, source).also {
it.viewer_flags = viewerFlags.toInt() it.viewer_flags = viewerFlags.toInt()
it.chapter_flags = chapterFlags.toInt() it.chapter_flags = chapterFlags.toInt()
it.cover_last_modified = coverLastModified it.cover_last_modified = coverLastModified
it.thumbnail_url = thumbnailUrl
} }
fun Manga.toMangaInfo(): MangaInfo = MangaInfo( fun Manga.toMangaInfo(): MangaInfo = MangaInfo(

View File

@ -378,11 +378,7 @@ class MangaController :
} }
.launchIn(viewScope) .launchIn(viewScope)
settingsSheet = ChaptersSettingsSheet(router, presenter) { group -> settingsSheet = ChaptersSettingsSheet(router, presenter)
if (group is ChaptersSettingsSheet.Filter.FilterGroup) {
updateFilterIconState()
}
}
trackSheet = TrackSheet(this, manga!!, (activity as MainActivity).supportFragmentManager) trackSheet = TrackSheet(this, manga!!, (activity as MainActivity).supportFragmentManager)
@ -1092,6 +1088,7 @@ class MangaController :
} }
updateFabVisibility() updateFabVisibility()
updateFilterIconState()
settingsSheet?.filters?.updateScanlatorFilter() settingsSheet?.filters?.updateScanlatorFilter()
} }

View File

@ -7,8 +7,10 @@ import android.view.View
import androidx.core.view.isVisible import androidx.core.view.isVisible
import com.bluelinelabs.conductor.Router import com.bluelinelabs.conductor.Router
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import eu.kanade.domain.manga.model.Manga
import eu.kanade.domain.manga.model.toTriStateGroupState
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.toDomainManga
import eu.kanade.tachiyomi.ui.manga.MangaPresenter import eu.kanade.tachiyomi.ui.manga.MangaPresenter
import eu.kanade.tachiyomi.util.lang.launchIO import eu.kanade.tachiyomi.util.lang.launchIO
import eu.kanade.tachiyomi.util.lang.withUIContext import eu.kanade.tachiyomi.util.lang.withUIContext
@ -17,29 +19,43 @@ import eu.kanade.tachiyomi.widget.ExtendedNavigationView
import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.State import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.State
import eu.kanade.tachiyomi.widget.sheet.TabbedBottomSheetDialog import eu.kanade.tachiyomi.widget.sheet.TabbedBottomSheetDialog
import exh.md.utils.MdUtil import exh.md.utils.MdUtil
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.cancel
import kotlinx.coroutines.supervisorScope import kotlinx.coroutines.supervisorScope
class ChaptersSettingsSheet( class ChaptersSettingsSheet(
private val router: Router, private val router: Router,
private val presenter: MangaPresenter, private val presenter: MangaPresenter,
private val onGroupClickListener: (ExtendedNavigationView.Group) -> Unit,
) : TabbedBottomSheetDialog(router.activity!!) { ) : TabbedBottomSheetDialog(router.activity!!) {
val filters = Filter(router.activity!!) private lateinit var scope: CoroutineScope
private val sort = Sort(router.activity!!)
private val display = Display(router.activity!!) private var manga: Manga? = null
val filters = Filter(context)
private val sort = Sort(context)
private val display = Display(context)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
filters.onGroupClicked = onGroupClickListener
sort.onGroupClicked = onGroupClickListener
display.onGroupClicked = onGroupClickListener
binding.menu.isVisible = true binding.menu.isVisible = true
binding.menu.setOnClickListener { it.post { showPopupMenu(it) } } binding.menu.setOnClickListener { it.post { showPopupMenu(it) } }
} }
override fun onAttachedToWindow() {
super.onAttachedToWindow()
scope = MainScope()
// TODO: Listen to changes
updateManga()
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
scope.cancel()
}
override fun getTabViews(): List<View> = listOf( override fun getTabViews(): List<View> = listOf(
filters, filters,
sort, sort,
@ -52,6 +68,10 @@ class ChaptersSettingsSheet(
R.string.action_display, R.string.action_display,
) )
private fun updateManga() {
manga = presenter.manga.toDomainManga()
}
private fun showPopupMenu(view: View) { private fun showPopupMenu(view: View) {
view.popupMenu( view.popupMenu(
menuRes = R.menu.default_chapter_filter, menuRes = R.menu.default_chapter_filter,
@ -88,6 +108,10 @@ class ChaptersSettingsSheet(
filterGroup.updateScanlatorFilter() filterGroup.updateScanlatorFilter()
} }
override fun updateView() {
filterGroup.updateModels()
}
inner class FilterGroup : Group { inner class FilterGroup : Group {
private val downloaded = Item.TriStateGroup(R.string.action_filter_downloaded, this) private val downloaded = Item.TriStateGroup(R.string.action_filter_downloaded, this)
@ -101,20 +125,30 @@ class ChaptersSettingsSheet(
override val footer: Item? = null override val footer: Item? = null
override fun initModels() { override fun initModels() {
if (presenter.forceDownloaded()) { val manga = manga ?: return
if (manga.forceDownloaded()) {
downloaded.state = State.INCLUDE.value downloaded.state = State.INCLUDE.value
downloaded.enabled = false downloaded.enabled = false
} else { } else {
downloaded.state = presenter.onlyDownloaded().value downloaded.state = manga.downloadedFilter.toTriStateGroupState().value
} }
unread.state = presenter.onlyUnread().value unread.state = manga.unreadFilter.toTriStateGroupState().value
bookmarked.state = presenter.onlyBookmarked().value bookmarked.state = manga.bookmarkedFilter.toTriStateGroupState().value
// SY -->
updateScanlatorFilter() updateScanlatorFilter()
// SY <--
} }
fun updateModels() {
initModels()
adapter.notifyItemRangeChanged(0, 3)
}
// SY -->
fun updateScanlatorFilter() { fun updateScanlatorFilter() {
scanlatorFilters.isVisible = presenter.allChapterScanlators.size > 1 scanlatorFilters.isVisible = presenter.allChapterScanlators.size > 1
} }
// SY <--
override fun onItemClicked(item: Item) { override fun onItemClicked(item: Item) {
if (item is Item.DrawableSelection) { if (item is Item.DrawableSelection) {
@ -156,7 +190,6 @@ class ChaptersSettingsSheet(
State.EXCLUDE.value -> State.IGNORE State.EXCLUDE.value -> State.IGNORE
else -> throw Exception("Unknown State") else -> throw Exception("Unknown State")
} }
item.state = newState.value
when (item) { when (item) {
downloaded -> presenter.setDownloadedFilter(newState) downloaded -> presenter.setDownloadedFilter(newState)
unread -> presenter.setUnreadFilter(newState) unread -> presenter.setUnreadFilter(newState)
@ -164,8 +197,9 @@ class ChaptersSettingsSheet(
else -> {} else -> {}
} }
initModels() // TODO: Remove
adapter.notifyItemChanged(items.indexOf(item), item) updateManga()
updateView()
} }
} }
} }
@ -176,8 +210,14 @@ class ChaptersSettingsSheet(
inner class Sort @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : inner class Sort @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
Settings(context, attrs) { Settings(context, attrs) {
private val group = SortGroup()
init { init {
setGroups(listOf(SortGroup())) setGroups(listOf(group))
}
override fun updateView() {
group.updateModels()
} }
inner class SortGroup : Group { inner class SortGroup : Group {
@ -191,8 +231,9 @@ class ChaptersSettingsSheet(
override val footer: Item? = null override val footer: Item? = null
override fun initModels() { override fun initModels() {
val sorting = presenter.manga.sorting val manga = manga ?: return
val order = if (presenter.manga.sortDescending()) { val sorting = manga.sorting
val order = if (manga.sortDescending()) {
Item.MultiSort.SORT_DESC Item.MultiSort.SORT_DESC
} else { } else {
Item.MultiSort.SORT_ASC Item.MultiSort.SORT_ASC
@ -206,29 +247,23 @@ class ChaptersSettingsSheet(
if (sorting == Manga.CHAPTER_SORTING_UPLOAD_DATE) order else Item.MultiSort.SORT_NONE if (sorting == Manga.CHAPTER_SORTING_UPLOAD_DATE) order else Item.MultiSort.SORT_NONE
} }
override fun onItemClicked(item: Item) { fun updateModels() {
items.forEachIndexed { i, multiSort -> initModels()
multiSort.state = if (multiSort == item) { adapter.notifyItemRangeChanged(0, 3)
when (item.state) { }
Item.MultiSort.SORT_NONE -> Item.MultiSort.SORT_ASC
Item.MultiSort.SORT_ASC -> Item.MultiSort.SORT_DESC
Item.MultiSort.SORT_DESC -> Item.MultiSort.SORT_ASC
else -> throw Exception("Unknown state")
}
} else {
Item.MultiSort.SORT_NONE
}
adapter.notifyItemChanged(i, multiSort)
}
override fun onItemClicked(item: Item) {
when (item) { when (item) {
source -> presenter.setSorting(Manga.CHAPTER_SORTING_SOURCE) source -> presenter.setSorting(Manga.CHAPTER_SORTING_SOURCE.toInt())
chapterNum -> presenter.setSorting(Manga.CHAPTER_SORTING_NUMBER) chapterNum -> presenter.setSorting(Manga.CHAPTER_SORTING_NUMBER.toInt())
uploadDate -> presenter.setSorting(Manga.CHAPTER_SORTING_UPLOAD_DATE) uploadDate -> presenter.setSorting(Manga.CHAPTER_SORTING_UPLOAD_DATE.toInt())
else -> throw Exception("Unknown sorting") else -> throw Exception("Unknown sorting")
} }
// TODO: Remove
presenter.reverseSortOrder() presenter.reverseSortOrder()
updateManga()
updateView()
} }
} }
} }
@ -239,8 +274,14 @@ class ChaptersSettingsSheet(
inner class Display @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : inner class Display @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
Settings(context, attrs) { Settings(context, attrs) {
private val group = DisplayGroup()
init { init {
setGroups(listOf(DisplayGroup())) setGroups(listOf(group))
}
override fun updateView() {
group.updateModels()
} }
inner class DisplayGroup : Group { inner class DisplayGroup : Group {
@ -253,25 +294,29 @@ class ChaptersSettingsSheet(
override val footer: Item? = null override val footer: Item? = null
override fun initModels() { override fun initModels() {
val mode = presenter.manga.displayMode val mode = manga?.displayMode ?: return
displayTitle.checked = mode == Manga.CHAPTER_DISPLAY_NAME displayTitle.checked = mode == Manga.CHAPTER_DISPLAY_NAME
displayChapterNum.checked = mode == Manga.CHAPTER_DISPLAY_NUMBER displayChapterNum.checked = mode == Manga.CHAPTER_DISPLAY_NUMBER
} }
fun updateModels() {
initModels()
adapter.notifyItemRangeChanged(0, 2)
}
override fun onItemClicked(item: Item) { override fun onItemClicked(item: Item) {
item as Item.Radio item as Item.Radio
if (item.checked) return if (item.checked) return
items.forEachIndexed { index, radio ->
radio.checked = item == radio
adapter.notifyItemChanged(index, radio)
}
when (item) { when (item) {
displayTitle -> presenter.setDisplayMode(Manga.CHAPTER_DISPLAY_NAME) displayTitle -> presenter.setDisplayMode(Manga.CHAPTER_DISPLAY_NAME.toInt())
displayChapterNum -> presenter.setDisplayMode(Manga.CHAPTER_DISPLAY_NUMBER) displayChapterNum -> presenter.setDisplayMode(Manga.CHAPTER_DISPLAY_NUMBER.toInt())
else -> throw NotImplementedError("Unknown display mode") else -> throw NotImplementedError("Unknown display mode")
} }
// TODO: Remove
updateManga()
updateView()
} }
} }
} }
@ -294,6 +339,9 @@ class ChaptersSettingsSheet(
addView(recycler) addView(recycler)
} }
open fun updateView() {
}
/** /**
* Adapter of the recycler view. * Adapter of the recycler view.
*/ */