Преглед на файлове

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

Currently breaks initial settings state until the source of truth is
properly updated.
Ivan Iskandar преди 2 години
родител
ревизия
005b9b595c

+ 88 - 1
app/src/main/java/eu/kanade/domain/manga/model/Manga.kt

@@ -1,8 +1,10 @@
 package eu.kanade.domain.manga.model
 
 import eu.kanade.tachiyomi.data.cache.CoverCache
+import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 import eu.kanade.tachiyomi.source.LocalSource
 import eu.kanade.tachiyomi.source.model.SManga
+import eu.kanade.tachiyomi.widget.ExtendedNavigationView
 import tachiyomi.source.model.MangaInfo
 import uy.kohesive.injekt.Injekt
 import uy.kohesive.injekt.api.get
@@ -45,15 +47,99 @@ 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
         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_NUMBER = 0x00000100L
         const val CHAPTER_SORTING_UPLOAD_DATE = 0x00000200L
         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
+    }
+}
+
+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
     }
 }
 
@@ -66,6 +152,7 @@ fun Manga.toDbManga(): DbManga = DbManga.create(url, title, source).also {
     it.viewer_flags = viewerFlags.toInt()
     it.chapter_flags = chapterFlags.toInt()
     it.cover_last_modified = coverLastModified
+    it.thumbnail_url = thumbnailUrl
 }
 
 fun Manga.toMangaInfo(): MangaInfo = MangaInfo(

+ 2 - 5
app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt

@@ -305,11 +305,7 @@ class MangaController :
             }
             .launchIn(viewScope)
 
-        settingsSheet = ChaptersSettingsSheet(router, presenter) { group ->
-            if (group is ChaptersSettingsSheet.Filter.FilterGroup) {
-                updateFilterIconState()
-            }
-        }
+        settingsSheet = ChaptersSettingsSheet(router, presenter)
 
         trackSheet = TrackSheet(this, manga!!, (activity as MainActivity).supportFragmentManager)
 
@@ -873,6 +869,7 @@ class MangaController :
         }
 
         updateFabVisibility()
+        updateFilterIconState()
     }
 
     private fun fetchChaptersFromSource(manualFetch: Boolean = false) {

+ 89 - 45
app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersSettingsSheet.kt

@@ -6,35 +6,51 @@ import android.util.AttributeSet
 import android.view.View
 import androidx.core.view.isVisible
 import com.bluelinelabs.conductor.Router
+import eu.kanade.domain.manga.model.Manga
+import eu.kanade.domain.manga.model.toTriStateGroupState
 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.util.view.popupMenu
 import eu.kanade.tachiyomi.widget.ExtendedNavigationView
 import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.State
 import eu.kanade.tachiyomi.widget.sheet.TabbedBottomSheetDialog
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.MainScope
+import kotlinx.coroutines.cancel
 
 class ChaptersSettingsSheet(
     private val router: Router,
     private val presenter: MangaPresenter,
-    private val onGroupClickListener: (ExtendedNavigationView.Group) -> Unit,
 ) : TabbedBottomSheetDialog(router.activity!!) {
 
-    val filters = Filter(router.activity!!)
-    private val sort = Sort(router.activity!!)
-    private val display = Display(router.activity!!)
+    private lateinit var scope: CoroutineScope
+
+    private var manga: Manga? = null
+
+    val filters = Filter(context)
+    private val sort = Sort(context)
+    private val display = Display(context)
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
 
-        filters.onGroupClicked = onGroupClickListener
-        sort.onGroupClicked = onGroupClickListener
-        display.onGroupClicked = onGroupClickListener
-
         binding.menu.isVisible = true
         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(
         filters,
         sort,
@@ -47,6 +63,10 @@ class ChaptersSettingsSheet(
         R.string.action_display,
     )
 
+    private fun updateManga() {
+        manga = presenter.manga.toDomainManga()
+    }
+
     private fun showPopupMenu(view: View) {
         view.popupMenu(
             menuRes = R.menu.default_chapter_filter,
@@ -79,6 +99,10 @@ class ChaptersSettingsSheet(
             return filterGroup.items.any { it.state != State.IGNORE.value }
         }
 
+        override fun updateView() {
+            filterGroup.updateModels()
+        }
+
         inner class FilterGroup : Group {
 
             private val downloaded = Item.TriStateGroup(R.string.action_filter_downloaded, this)
@@ -90,14 +114,20 @@ class ChaptersSettingsSheet(
             override val footer: Item? = null
 
             override fun initModels() {
-                if (presenter.forceDownloaded()) {
+                val manga = manga ?: return
+                if (manga.forceDownloaded()) {
                     downloaded.state = State.INCLUDE.value
                     downloaded.enabled = false
                 } else {
-                    downloaded.state = presenter.onlyDownloaded().value
+                    downloaded.state = manga.downloadedFilter.toTriStateGroupState().value
                 }
-                unread.state = presenter.onlyUnread().value
-                bookmarked.state = presenter.onlyBookmarked().value
+                unread.state = manga.unreadFilter.toTriStateGroupState().value
+                bookmarked.state = manga.bookmarkedFilter.toTriStateGroupState().value
+            }
+
+            fun updateModels() {
+                initModels()
+                adapter.notifyItemRangeChanged(0, 3)
             }
 
             override fun onItemClicked(item: Item) {
@@ -108,7 +138,6 @@ class ChaptersSettingsSheet(
                     State.EXCLUDE.value -> State.IGNORE
                     else -> throw Exception("Unknown State")
                 }
-                item.state = newState.value
                 when (item) {
                     downloaded -> presenter.setDownloadedFilter(newState)
                     unread -> presenter.setUnreadFilter(newState)
@@ -116,8 +145,9 @@ class ChaptersSettingsSheet(
                     else -> {}
                 }
 
-                initModels()
-                adapter.notifyItemChanged(items.indexOf(item), item)
+                // TODO: Remove
+                updateManga()
+                updateView()
             }
         }
     }
@@ -128,8 +158,14 @@ class ChaptersSettingsSheet(
     inner class Sort @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
         Settings(context, attrs) {
 
+        private val group = SortGroup()
+
         init {
-            setGroups(listOf(SortGroup()))
+            setGroups(listOf(group))
+        }
+
+        override fun updateView() {
+            group.updateModels()
         }
 
         inner class SortGroup : Group {
@@ -143,8 +179,9 @@ class ChaptersSettingsSheet(
             override val footer: Item? = null
 
             override fun initModels() {
-                val sorting = presenter.manga.sorting
-                val order = if (presenter.manga.sortDescending()) {
+                val manga = manga ?: return
+                val sorting = manga.sorting
+                val order = if (manga.sortDescending()) {
                     Item.MultiSort.SORT_DESC
                 } else {
                     Item.MultiSort.SORT_ASC
@@ -158,29 +195,23 @@ class ChaptersSettingsSheet(
                     if (sorting == Manga.CHAPTER_SORTING_UPLOAD_DATE) order else Item.MultiSort.SORT_NONE
             }
 
-            override fun onItemClicked(item: Item) {
-                items.forEachIndexed { i, multiSort ->
-                    multiSort.state = if (multiSort == item) {
-                        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)
-                }
+            fun updateModels() {
+                initModels()
+                adapter.notifyItemRangeChanged(0, 3)
+            }
 
+            override fun onItemClicked(item: Item) {
                 when (item) {
-                    source -> presenter.setSorting(Manga.CHAPTER_SORTING_SOURCE)
-                    chapterNum -> presenter.setSorting(Manga.CHAPTER_SORTING_NUMBER)
-                    uploadDate -> presenter.setSorting(Manga.CHAPTER_SORTING_UPLOAD_DATE)
+                    source -> presenter.setSorting(Manga.CHAPTER_SORTING_SOURCE.toInt())
+                    chapterNum -> presenter.setSorting(Manga.CHAPTER_SORTING_NUMBER.toInt())
+                    uploadDate -> presenter.setSorting(Manga.CHAPTER_SORTING_UPLOAD_DATE.toInt())
                     else -> throw Exception("Unknown sorting")
                 }
 
+                // TODO: Remove
                 presenter.reverseSortOrder()
+                updateManga()
+                updateView()
             }
         }
     }
@@ -191,8 +222,14 @@ class ChaptersSettingsSheet(
     inner class Display @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
         Settings(context, attrs) {
 
+        private val group = DisplayGroup()
+
         init {
-            setGroups(listOf(DisplayGroup()))
+            setGroups(listOf(group))
+        }
+
+        override fun updateView() {
+            group.updateModels()
         }
 
         inner class DisplayGroup : Group {
@@ -205,25 +242,29 @@ class ChaptersSettingsSheet(
             override val footer: Item? = null
 
             override fun initModels() {
-                val mode = presenter.manga.displayMode
+                val mode = manga?.displayMode ?: return
                 displayTitle.checked = mode == Manga.CHAPTER_DISPLAY_NAME
                 displayChapterNum.checked = mode == Manga.CHAPTER_DISPLAY_NUMBER
             }
 
+            fun updateModels() {
+                initModels()
+                adapter.notifyItemRangeChanged(0, 2)
+            }
+
             override fun onItemClicked(item: Item) {
                 item as Item.Radio
                 if (item.checked) return
 
-                items.forEachIndexed { index, radio ->
-                    radio.checked = item == radio
-                    adapter.notifyItemChanged(index, radio)
-                }
-
                 when (item) {
-                    displayTitle -> presenter.setDisplayMode(Manga.CHAPTER_DISPLAY_NAME)
-                    displayChapterNum -> presenter.setDisplayMode(Manga.CHAPTER_DISPLAY_NUMBER)
+                    displayTitle -> presenter.setDisplayMode(Manga.CHAPTER_DISPLAY_NAME.toInt())
+                    displayChapterNum -> presenter.setDisplayMode(Manga.CHAPTER_DISPLAY_NUMBER.toInt())
                     else -> throw NotImplementedError("Unknown display mode")
                 }
+
+                // TODO: Remove
+                updateManga()
+                updateView()
             }
         }
     }
@@ -246,6 +287,9 @@ class ChaptersSettingsSheet(
             addView(recycler)
         }
 
+        open fun updateView() {
+        }
+
         /**
          * Adapter of the recycler view.
          */