Quellcode durchsuchen

MangaController optimizations (#6089)

* MangaController: Fix ignored stable ids

* MangaController: Replace notifyDataSetChanged

* ChaptersSettingsSheet: Optimizations
Ivan Iskandar vor 3 Jahren
Ursprung
Commit
684965f3e5

+ 24 - 21
app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt

@@ -85,7 +85,6 @@ import eu.kanade.tachiyomi.ui.webview.WebViewActivity
 import eu.kanade.tachiyomi.util.chapter.NoChaptersException
 import eu.kanade.tachiyomi.util.hasCustomCover
 import eu.kanade.tachiyomi.util.lang.launchIO
-import eu.kanade.tachiyomi.util.lang.launchUI
 import eu.kanade.tachiyomi.util.storage.getUriCompat
 import eu.kanade.tachiyomi.util.system.logcat
 import eu.kanade.tachiyomi.util.system.toShareIntent
@@ -249,13 +248,21 @@ class MangaController :
         if (manga == null || source == null) return
 
         // Init RecyclerView and adapter
-        mangaInfoAdapter = MangaInfoHeaderAdapter(this, fromSource, binding.infoRecycler != null)
-        chaptersHeaderAdapter = MangaChaptersHeaderAdapter(this)
+        mangaInfoAdapter = MangaInfoHeaderAdapter(this, fromSource, binding.infoRecycler != null).apply {
+            setHasStableIds(true)
+        }
+        chaptersHeaderAdapter = MangaChaptersHeaderAdapter(this).apply {
+            setHasStableIds(true)
+        }
         chaptersAdapter = ChaptersAdapter(this, view.context)
 
         // Phone layout
         binding.fullRecycler?.let {
-            it.adapter = ConcatAdapter(mangaInfoAdapter, chaptersHeaderAdapter, chaptersAdapter)
+            val config = ConcatAdapter.Config.Builder()
+                .setIsolateViewTypes(true)
+                .setStableIdMode(ConcatAdapter.Config.StableIdMode.SHARED_STABLE_IDS)
+                .build()
+            it.adapter = ConcatAdapter(config, mangaInfoAdapter, chaptersHeaderAdapter, chaptersAdapter)
 
             // Skips directly to chapters list if navigated to from the library
             it.post {
@@ -318,7 +325,6 @@ class MangaController :
         settingsSheet = ChaptersSettingsSheet(router, presenter) { group ->
             if (group is ChaptersSettingsSheet.Filter.FilterGroup) {
                 updateFilterIconState()
-                chaptersAdapter?.notifyDataSetChanged()
             }
         }
 
@@ -620,7 +626,7 @@ class MangaController :
                 }
             }
         }
-        mangaInfoAdapter?.notifyDataSetChanged()
+        mangaInfoAdapter?.update()
     }
 
     fun onCategoriesClick() {
@@ -818,7 +824,7 @@ class MangaController :
 
     override fun deleteMangaCover(manga: Manga) {
         presenter.deleteCustomCover(manga)
-        mangaInfoAdapter?.notifyDataSetChanged()
+        mangaInfoAdapter?.notifyItemChanged(0, manga)
         destroyActionModeIfNeeded()
     }
 
@@ -832,7 +838,7 @@ class MangaController :
     }
 
     fun onSetCoverSuccess() {
-        mangaInfoAdapter?.notifyDataSetChanged()
+        mangaInfoAdapter?.notifyItemChanged(0, this)
         (dialog as? MangaFullCoverDialog)?.setImage(manga)
         activity?.toast(R.string.cover_updated)
     }
@@ -943,19 +949,20 @@ class MangaController :
         val lastClickPosition = lastClickPositionStack.peek()!!
         when {
             lastClickPosition == -1 -> setSelection(position)
-            lastClickPosition > position ->
-                for (i in position until lastClickPosition)
-                    setSelection(i)
-            lastClickPosition < position ->
-                for (i in lastClickPosition + 1..position)
-                    setSelection(i)
+            lastClickPosition > position -> {
+                for (i in position until lastClickPosition) setSelection(i)
+                chaptersAdapter?.notifyItemRangeChanged(position, lastClickPosition, position)
+            }
+            lastClickPosition < position -> {
+                for (i in lastClickPosition + 1..position) setSelection(i)
+                chaptersAdapter?.notifyItemRangeChanged(lastClickPosition + 1, position, position)
+            }
             else -> setSelection(position)
         }
         if (lastClickPosition != position) {
             lastClickPositionStack.remove(position) // move to top if already exists
             lastClickPositionStack.push(position)
         }
-        chaptersAdapter?.notifyDataSetChanged()
     }
 
     fun showSettingsSheet() {
@@ -968,7 +975,6 @@ class MangaController :
         val adapter = chaptersAdapter ?: return
         val item = adapter.getItem(position) ?: return
         adapter.toggleSelection(position)
-        adapter.notifyDataSetChanged()
         if (adapter.isSelected(position)) {
             selectedChapters.add(item)
         } else {
@@ -1101,11 +1107,11 @@ class MangaController :
         selectedChapters.clear()
         for (i in 0..adapter.itemCount) {
             adapter.toggleSelection(i)
+            adapter.notifyItemChanged(i, i)
         }
         selectedChapters.addAll(adapter.selectedPositions.mapNotNull { adapter.getItem(it) })
 
         actionMode?.invalidate()
-        adapter.notifyDataSetChanged()
     }
 
     private fun markAsRead(chapters: List<ChapterItem>) {
@@ -1172,10 +1178,7 @@ class MangaController :
     fun onChaptersDeleted(chapters: List<ChapterItem>) {
         // this is needed so the downloaded text gets removed from the item
         chapters.forEach {
-            chaptersAdapter?.updateItem(it)
-        }
-        launchUI {
-            chaptersAdapter?.notifyDataSetChanged()
+            chaptersAdapter?.updateItem(it, it)
         }
     }
 

+ 1 - 0
app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt

@@ -718,6 +718,7 @@ class MangaPresenter(
     fun setDisplayMode(mode: Int) {
         manga.displayMode = mode
         db.updateChapterFlags(manga).executeAsBlocking()
+        refreshChapters()
     }
 
     /**

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

@@ -116,7 +116,7 @@ class ChaptersSettingsSheet(
                 }
 
                 initModels()
-                item.group.items.forEach { adapter.notifyItemChanged(it) }
+                adapter.notifyItemChanged(items.indexOf(item), item)
             }
         }
     }
@@ -158,18 +158,18 @@ class ChaptersSettingsSheet(
             }
 
             override fun onItemClicked(item: Item) {
-                item as Item.MultiStateGroup
-                val prevState = item.state
-
-                item.group.items.forEach {
-                    (it as Item.MultiStateGroup).state =
+                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
-                }
-                item.state = when (prevState) {
-                    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")
+                    }
+                    adapter.notifyItemChanged(i, multiSort)
                 }
 
                 when (item) {
@@ -180,8 +180,6 @@ class ChaptersSettingsSheet(
                 }
 
                 presenter.reverseSortOrder()
-
-                item.group.items.forEach { adapter.notifyItemChanged(it) }
             }
         }
     }
@@ -215,16 +213,16 @@ class ChaptersSettingsSheet(
                 item as Item.Radio
                 if (item.checked) return
 
-                item.group.items.forEach { (it as Item.Radio).checked = false }
-                item.checked = true
+                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)
                     else -> throw NotImplementedError("Unknown display mode")
                 }
-
-                item.group.items.forEach { adapter.notifyItemChanged(it) }
             }
         }
     }

+ 4 - 4
app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/MangaChaptersHeaderAdapter.kt

@@ -30,20 +30,20 @@ class MangaChaptersHeaderAdapter(
 
     override fun getItemCount(): Int = 1
 
+    override fun getItemId(position: Int): Long = hashCode().toLong()
+
     override fun onBindViewHolder(holder: HeaderViewHolder, position: Int) {
         holder.bind()
     }
 
     fun setNumChapters(numChapters: Int) {
         this.numChapters = numChapters
-
-        notifyDataSetChanged()
+        notifyItemChanged(0, this)
     }
 
     fun setHasActiveFilters(hasActiveFilters: Boolean) {
         this.hasActiveFilters = hasActiveFilters
-
-        notifyDataSetChanged()
+        notifyItemChanged(0, this)
     }
 
     inner class HeaderViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {

+ 7 - 3
app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoHeaderAdapter.kt

@@ -56,6 +56,8 @@ class MangaInfoHeaderAdapter(
 
     override fun getItemCount(): Int = 1
 
+    override fun getItemId(position: Int): Long = hashCode().toLong()
+
     override fun onBindViewHolder(holder: HeaderViewHolder, position: Int) {
         holder.bind()
     }
@@ -69,14 +71,16 @@ class MangaInfoHeaderAdapter(
     fun update(manga: Manga, source: Source) {
         this.manga = manga
         this.source = source
+        update()
+    }
 
-        notifyDataSetChanged()
+    fun update() {
+        notifyItemChanged(0, this)
     }
 
     fun setTrackingCount(trackCount: Int) {
         this.trackCount = trackCount
-
-        notifyDataSetChanged()
+        update()
     }
 
     private fun updateCoverPosition() {