diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt index 5cd813949..bcd94ae5f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt @@ -55,7 +55,6 @@ import eu.kanade.tachiyomi.source.LocalSource import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.online.HttpSource -import eu.kanade.tachiyomi.source.online.MetadataSource import eu.kanade.tachiyomi.ui.base.controller.DialogController import eu.kanade.tachiyomi.ui.base.controller.FabController import eu.kanade.tachiyomi.ui.base.controller.NucleusController @@ -94,7 +93,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 @@ -105,7 +103,6 @@ import eu.kanade.tachiyomi.util.view.snack import eu.kanade.tachiyomi.widget.materialdialogs.QuadStateTextView import exh.log.xLogD import exh.md.similar.MangaDexSimilarController -import exh.metadata.metadata.base.FlatMetadata import exh.metadata.metadata.base.RaisedSearchMetadata import exh.recs.RecommendsController import exh.source.MERGED_SOURCE_ID @@ -304,18 +301,29 @@ 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) // SY --> if (!preferences.recommendsInOverflow().get() || smartSearchConfig != null) { - mangaInfoButtonsAdapter = MangaInfoButtonsAdapter(this) + mangaInfoButtonsAdapter = MangaInfoButtonsAdapter(this).apply { + setHasStableIds(true) + } } // SY <-- // Phone layout binding.fullRecycler?.let { + val config = ConcatAdapter.Config.Builder() + .setIsolateViewTypes(true) + .setStableIdMode(ConcatAdapter.Config.StableIdMode.SHARED_STABLE_IDS) + .build() it.adapter = ConcatAdapter( + config, listOfNotNull( mangaInfoAdapter, mangaInfoButtonsAdapter, @@ -390,7 +398,6 @@ class MangaController : settingsSheet = ChaptersSettingsSheet(router, presenter) { group -> if (group is ChaptersSettingsSheet.Filter.FilterGroup) { updateFilterIconState() - chaptersAdapter?.notifyDataSetChanged() } } @@ -569,17 +576,6 @@ class MangaController : // Manga info - start - // SY --> - fun onNextMetaInfo(flatMetadata: FlatMetadata) { - val mainSource = presenter.source.getMainSource>() - if (mainSource != null) { - presenter.meta = flatMetadata.raise(mainSource.metaClass) - mangaInfoAdapter?.notifyMetaAdapter() - updateFilterIconState() - } - } - // SY <-- - /** * Check if manga is initialized. * If true update header with manga information, @@ -834,7 +830,7 @@ class MangaController : } } } - mangaInfoAdapter?.notifyDataSetChanged() + mangaInfoAdapter?.update() } fun onCategoriesClick() { @@ -1038,7 +1034,7 @@ class MangaController : override fun deleteMangaCover(manga: Manga) { presenter.deleteCustomCover(manga) - mangaInfoAdapter?.notifyDataSetChanged() + mangaInfoAdapter?.notifyItemChanged(0, manga) destroyActionModeIfNeeded() } @@ -1057,7 +1053,7 @@ class MangaController : fun onSetCoverSuccess() { editMangaDialog?.loadCover() - mangaInfoAdapter?.notifyDataSetChanged() + mangaInfoAdapter?.notifyItemChanged(0, this) (dialog as? MangaFullCoverDialog)?.setImage(manga) activity?.toast(R.string.cover_updated) } @@ -1172,19 +1168,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() { @@ -1197,7 +1194,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 { @@ -1330,11 +1326,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) { @@ -1401,10 +1397,7 @@ class MangaController : fun onChaptersDeleted(chapters: List) { // this is needed so the downloaded text gets removed from the item chapters.forEach { - chaptersAdapter?.updateItem(it) - } - launchUI { - chaptersAdapter?.notifyDataSetChanged() + chaptersAdapter?.updateItem(it, it) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt index db902a3e5..c8eae4dd2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt @@ -1106,6 +1106,7 @@ class MangaPresenter( fun setDisplayMode(mode: Int) { manga.displayMode = mode db.updateChapterFlags(manga).executeAsBlocking() + refreshChapters() } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersSettingsSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersSettingsSheet.kt index b2df6b3f0..84c6d1ea0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersSettingsSheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersSettingsSheet.kt @@ -155,7 +155,7 @@ class ChaptersSettingsSheet( } initModels() - item.group.items.forEach { adapter.notifyItemChanged(it) } + adapter.notifyItemChanged(items.indexOf(item), item) } } } @@ -197,18 +197,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) { @@ -219,8 +219,6 @@ class ChaptersSettingsSheet( } presenter.reverseSortOrder() - - item.group.items.forEach { adapter.notifyItemChanged(it) } } } } @@ -254,16 +252,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) } } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/MangaChaptersHeaderAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/MangaChaptersHeaderAdapter.kt index 72e634c16..4ae569a63 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/MangaChaptersHeaderAdapter.kt +++ b/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) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoHeaderAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoHeaderAdapter.kt index 0fb08745a..ba2a3eb32 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoHeaderAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoHeaderAdapter.kt @@ -66,7 +66,9 @@ class MangaInfoHeaderAdapter( binding.mangaSummarySection.expanded = fromSource || isTablet // SY --> - metaInfoAdapter = source.getMainSource>()?.getDescriptionAdapter(controller) + metaInfoAdapter = source.getMainSource>()?.getDescriptionAdapter(controller)?.apply { + setHasStableIds(true) + } binding.metadataView.isVisible = if (metaInfoAdapter != null) { binding.metadataView.layoutManager = LinearLayoutManager(binding.root.context) binding.metadataView.adapter = metaInfoAdapter @@ -81,6 +83,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() } @@ -98,15 +102,17 @@ class MangaInfoHeaderAdapter( this.meta = meta this.mergedMangaReferences = mergedMangaReferences // SY <-- + update() + updateMetaAdapter() + } - notifyDataSetChanged() - notifyMetaAdapter() + fun update() { + notifyItemChanged(0, this) } fun setTrackingCount(trackCount: Int) { this.trackCount = trackCount - - notifyDataSetChanged() + update() } private fun updateCoverPosition() { @@ -116,7 +122,7 @@ class MangaInfoHeaderAdapter( } } - fun notifyMetaAdapter() { + private fun updateMetaAdapter() { metaInfoAdapter?.notifyDataSetChanged() }