Refactor adapters

This commit is contained in:
Koitharu
2023-07-06 06:53:23 +03:00
parent 7908eb1441
commit 394479192b
43 changed files with 249 additions and 434 deletions

View File

@@ -2,7 +2,7 @@ package org.koitharu.kotatsu.bookmarks.data
import org.koitharu.kotatsu.bookmarks.domain.Bookmark
import org.koitharu.kotatsu.parsers.model.Manga
import java.util.*
import java.util.Date
fun BookmarkEntity.toBookmark(manga: Manga) = Bookmark(
manga = manga,
@@ -30,4 +30,5 @@ fun Collection<BookmarkEntity>.toBookmarks(manga: Manga) = map {
it.toBookmark(manga)
}
fun Collection<Bookmark>.ids() = map { it.pageId }
@JvmName("bookmarksIds")
fun Collection<Bookmark>.ids() = map { it.pageId }

View File

@@ -1,5 +1,6 @@
package org.koitharu.kotatsu.bookmarks.domain
import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaPage
import java.util.Date
@@ -13,11 +14,21 @@ class Bookmark(
val imageUrl: String,
val createdAt: Date,
val percent: Float,
) {
) : ListModel {
val directImageUrl: String?
get() = if (isImageUrlDirect()) imageUrl else null
val imageLoadData: Any
get() = if (isImageUrlDirect()) imageUrl else toMangaPage()
override fun areItemsTheSame(other: ListModel): Boolean {
return other is Bookmark &&
manga.id == other.manga.id &&
chapterId == other.chapterId &&
page == other.page
}
fun toMangaPage() = MangaPage(
id = pageId,
url = imageUrl,

View File

@@ -28,8 +28,7 @@ fun bookmarkListAD(
binding.root.setOnLongClickListener(listener)
bind {
val data: Any = item.directImageUrl ?: item.toMangaPage()
binding.imageViewThumb.newImageRequest(lifecycleOwner, data)?.run {
binding.imageViewThumb.newImageRequest(lifecycleOwner, item.imageLoadData)?.run {
size(CoverSizeResolver(binding.imageViewThumb))
placeholder(R.drawable.ic_placeholder)
fallback(R.drawable.ic_placeholder)

View File

@@ -1,32 +1,15 @@
package org.koitharu.kotatsu.bookmarks.ui.adapter
import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.DiffUtil
import coil.ImageLoader
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
import org.koitharu.kotatsu.bookmarks.domain.Bookmark
import org.koitharu.kotatsu.core.ui.BaseListAdapter
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
class BookmarksAdapter(
coil: ImageLoader,
lifecycleOwner: LifecycleOwner,
clickListener: OnListItemClickListener<Bookmark>,
) : AsyncListDifferDelegationAdapter<Bookmark>(
DiffCallback(),
) : BaseListAdapter<Bookmark>(
bookmarkListAD(coil, lifecycleOwner, clickListener),
) {
private class DiffCallback : DiffUtil.ItemCallback<Bookmark>() {
override fun areItemsTheSame(oldItem: Bookmark, newItem: Bookmark): Boolean {
return oldItem.manga.id == newItem.manga.id &&
oldItem.chapterId == newItem.chapterId &&
oldItem.page == newItem.page
}
override fun areContentsTheSame(oldItem: Bookmark, newItem: Bookmark): Boolean {
return oldItem.imageUrl == newItem.imageUrl
}
}
}
)

View File

@@ -3,12 +3,11 @@ package org.koitharu.kotatsu.bookmarks.ui.adapter
import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.RecyclerView
import coil.ImageLoader
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
import org.koitharu.kotatsu.bookmarks.domain.Bookmark
import org.koitharu.kotatsu.bookmarks.ui.model.BookmarksGroup
import org.koitharu.kotatsu.core.ui.BaseListAdapter
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.core.ui.list.SectionedSelectionController
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
import org.koitharu.kotatsu.list.ui.adapter.ListStateHolderListener
import org.koitharu.kotatsu.list.ui.adapter.emptyStateListAD
import org.koitharu.kotatsu.list.ui.adapter.errorStateListAD
@@ -24,7 +23,7 @@ class BookmarksGroupAdapter(
listener: ListStateHolderListener,
bookmarkClickListener: OnListItemClickListener<Bookmark>,
groupClickListener: OnListItemClickListener<BookmarksGroup>,
) : AsyncListDifferDelegationAdapter<ListModel>(ListModelDiffCallback) {
) : BaseListAdapter<ListModel>() {
init {
val pool = RecyclerView.RecycledViewPool()

View File

@@ -4,7 +4,6 @@ import org.koitharu.kotatsu.bookmarks.domain.Bookmark
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.util.areItemsEquals
class BookmarksGroup(
val manga: Manga,
@@ -31,14 +30,12 @@ class BookmarksGroup(
if (manga != other.manga) return false
return bookmarks.areItemsEquals(other.bookmarks) { a, b ->
a.imageUrl == b.imageUrl
}
return bookmarks == other.bookmarks
}
override fun hashCode(): Int {
var result = manga.hashCode()
result = 31 * result + bookmarks.sumOf { it.imageUrl.hashCode() }
result = 31 * result + bookmarks.hashCode()
return result
}
}

View File

@@ -2,8 +2,10 @@ package org.koitharu.kotatsu.core.model
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.parsers.model.SortOrder
import java.util.*
import java.util.Date
@Parcelize
data class FavouriteCategory(
@@ -14,4 +16,20 @@ data class FavouriteCategory(
val createdAt: Date,
val isTrackingEnabled: Boolean,
val isVisibleInLibrary: Boolean,
) : Parcelable
) : Parcelable, ListModel {
override fun areItemsTheSame(other: ListModel): Boolean {
return other is FavouriteCategory && id == other.id
}
override fun getChangePayload(previousState: ListModel): Any? {
if (previousState !is FavouriteCategory) {
return null
}
return if (isTrackingEnabled != previousState.isTrackingEnabled || isVisibleInLibrary != isVisibleInLibrary) {
ListModelDiffCallback.PAYLOAD_CHECKED_CHANGED
} else {
null
}
}
}

View File

@@ -12,24 +12,24 @@ import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
import org.koitharu.kotatsu.list.ui.model.ListModel
import kotlin.coroutines.suspendCoroutine
open class BaseListAdapter(
vararg delegates: AdapterDelegate<List<ListModel>>,
) : AsyncListDifferDelegationAdapter<ListModel>(
AsyncDifferConfig.Builder(ListModelDiffCallback)
open class BaseListAdapter<T : ListModel>(
vararg delegates: AdapterDelegate<List<T>>,
) : AsyncListDifferDelegationAdapter<T>(
AsyncDifferConfig.Builder(ListModelDiffCallback<T>())
.setBackgroundThreadExecutor(Dispatchers.Default.limitedParallelism(2).asExecutor())
.build(),
*delegates,
), FlowCollector<List<ListModel>> {
), FlowCollector<List<T>> {
override suspend fun emit(value: List<ListModel>) = suspendCoroutine { cont ->
override suspend fun emit(value: List<T>) = suspendCoroutine { cont ->
setItems(value, ContinuationResumeRunnable(cont))
}
fun addListListener(listListener: ListListener<ListModel>) {
fun addListListener(listListener: ListListener<T>) {
differ.addListListener(listListener)
}
fun removeListListener(listListener: ListListener<ListModel>) {
fun removeListListener(listListener: ListListener<T>) {
differ.removeListListener(listListener)
}
}

View File

@@ -47,6 +47,7 @@ import org.koitharu.kotatsu.history.data.PROGRESS_NONE
import org.koitharu.kotatsu.image.ui.ImageActivity
import org.koitharu.kotatsu.list.domain.ListExtraProvider
import org.koitharu.kotatsu.list.ui.adapter.mangaGridItemAD
import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.list.ui.model.MangaItemModel
import org.koitharu.kotatsu.list.ui.size.StaticItemSizeResolver
import org.koitharu.kotatsu.main.ui.owners.NoModalBottomSheetOwner
@@ -207,7 +208,9 @@ class DetailsFragment :
return
}
val rv = viewBinding?.recyclerViewRelated ?: return
val adapter = (rv.adapter as? BaseListAdapter) ?: BaseListAdapter(
@Suppress("UNCHECKED_CAST")
val adapter = (rv.adapter as? BaseListAdapter<ListModel>) ?: BaseListAdapter(
mangaGridItemAD(
coil, viewLifecycleOwner,
StaticItemSizeResolver(resources.getDimensionPixelSize(R.dimen.smaller_grid_width)),

View File

@@ -1,16 +1,14 @@
package org.koitharu.kotatsu.details.ui.adapter
import android.content.Context
import androidx.recyclerview.widget.DiffUtil
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
import org.koitharu.kotatsu.core.ui.BaseListAdapter
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.core.ui.list.fastscroll.FastScroller
import org.koitharu.kotatsu.details.ui.model.ChapterListItem
import kotlin.jvm.internal.Intrinsics
class ChaptersAdapter(
onItemClickListener: OnListItemClickListener<ChapterListItem>,
) : AsyncListDifferDelegationAdapter<ChapterListItem>(DiffCallback()), FastScroller.SectionIndexer {
) : BaseListAdapter<ChapterListItem>(), FastScroller.SectionIndexer {
init {
setHasStableIds(true)
@@ -21,27 +19,6 @@ class ChaptersAdapter(
return items[position].chapter.id
}
private class DiffCallback : DiffUtil.ItemCallback<ChapterListItem>() {
override fun areItemsTheSame(oldItem: ChapterListItem, newItem: ChapterListItem): Boolean {
return oldItem.chapter.id == newItem.chapter.id
}
override fun areContentsTheSame(
oldItem: ChapterListItem,
newItem: ChapterListItem
): Boolean {
return Intrinsics.areEqual(oldItem, newItem)
}
override fun getChangePayload(oldItem: ChapterListItem, newItem: ChapterListItem): Any? {
if (oldItem.flags != newItem.flags && oldItem.chapter == newItem.chapter) {
return newItem.flags
}
return null
}
}
override fun getSectionText(context: Context, position: Int): CharSequence? {
val item = items.getOrNull(position) ?: return null
return item.chapter.number.toString()

View File

@@ -1,13 +1,14 @@
package org.koitharu.kotatsu.details.ui.model
import android.text.format.DateUtils
import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.parsers.model.MangaChapter
class ChapterListItem(
val chapter: MangaChapter,
val flags: Int,
private val uploadDateMs: Long,
) {
) : ListModel {
var uploadDate: CharSequence? = null
private set
@@ -50,6 +51,21 @@ class ChapterListItem(
return (flags and flag) == flag
}
override fun areItemsTheSame(other: ListModel): Boolean {
return other is ChapterListItem && chapter.id == other.chapter.id
}
override fun getChangePayload(previousState: ListModel): Any? {
if (previousState !is ChapterListItem) {
return super.getChangePayload(previousState)
}
return if (chapter == previousState.chapter && flags != previousState.flags) {
flags
} else {
super.getChangePayload(previousState)
}
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false

View File

@@ -3,15 +3,14 @@ package org.koitharu.kotatsu.details.ui.scrobbling
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.LifecycleOwner
import coil.ImageLoader
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
import org.koitharu.kotatsu.core.ui.BaseListAdapter
import org.koitharu.kotatsu.list.ui.model.ListModel
class ScrollingInfoAdapter(
lifecycleOwner: LifecycleOwner,
coil: ImageLoader,
fragmentManager: FragmentManager,
) : AsyncListDifferDelegationAdapter<ListModel>(ListModelDiffCallback) {
) : BaseListAdapter<ListModel>() {
init {
delegatesManager.addDelegate(scrobblingInfoAD(lifecycleOwner, coil, fragmentManager))

View File

@@ -2,8 +2,7 @@ package org.koitharu.kotatsu.download.ui.list
import androidx.lifecycle.LifecycleOwner
import coil.ImageLoader
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
import org.koitharu.kotatsu.core.ui.BaseListAdapter
import org.koitharu.kotatsu.list.ui.adapter.emptyStateListAD
import org.koitharu.kotatsu.list.ui.adapter.listHeaderAD
import org.koitharu.kotatsu.list.ui.adapter.loadingStateAD
@@ -13,7 +12,7 @@ class DownloadsAdapter(
lifecycleOwner: LifecycleOwner,
coil: ImageLoader,
listener: DownloadItemListener,
) : AsyncListDifferDelegationAdapter<ListModel>(ListModelDiffCallback) {
) : BaseListAdapter<ListModel>() {
init {
delegatesManager.addDelegate(ITEM_TYPE_DOWNLOAD, downloadItemAD(lifecycleOwner, coil, listener))

View File

@@ -2,10 +2,9 @@ package org.koitharu.kotatsu.explore.ui.adapter
import androidx.lifecycle.LifecycleOwner
import coil.ImageLoader
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
import org.koitharu.kotatsu.core.ui.BaseListAdapter
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.explore.ui.model.MangaSourceItem
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
import org.koitharu.kotatsu.list.ui.adapter.emptyHintAD
import org.koitharu.kotatsu.list.ui.adapter.listHeaderAD
import org.koitharu.kotatsu.list.ui.adapter.loadingStateAD
@@ -16,7 +15,7 @@ class ExploreAdapter(
lifecycleOwner: LifecycleOwner,
listener: ExploreListEventListener,
clickListener: OnListItemClickListener<MangaSourceItem>,
) : AsyncListDifferDelegationAdapter<ListModel>(ListModelDiffCallback) {
) : BaseListAdapter<ListModel>() {
init {
delegatesManager

View File

@@ -2,9 +2,8 @@ package org.koitharu.kotatsu.favourites.ui.categories.adapter
import androidx.lifecycle.LifecycleOwner
import coil.ImageLoader
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
import org.koitharu.kotatsu.core.ui.BaseListAdapter
import org.koitharu.kotatsu.favourites.ui.categories.FavouriteCategoriesListListener
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
import org.koitharu.kotatsu.list.ui.adapter.ListStateHolderListener
import org.koitharu.kotatsu.list.ui.adapter.emptyStateListAD
import org.koitharu.kotatsu.list.ui.adapter.loadingStateAD
@@ -15,7 +14,7 @@ class CategoriesAdapter(
lifecycleOwner: LifecycleOwner,
onItemClickListener: FavouriteCategoriesListListener,
listListener: ListStateHolderListener,
) : AsyncListDifferDelegationAdapter<ListModel>(ListModelDiffCallback) {
) : BaseListAdapter<ListModel>() {
init {
delegatesManager.addDelegate(categoryAD(coil, lifecycleOwner, onItemClickListener))

View File

@@ -1,44 +1,16 @@
package org.koitharu.kotatsu.favourites.ui.categories.select.adapter
import androidx.recyclerview.widget.DiffUtil
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
import org.koitharu.kotatsu.core.ui.BaseListAdapter
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.favourites.ui.categories.select.model.CategoriesHeaderItem
import org.koitharu.kotatsu.favourites.ui.categories.select.model.MangaCategoryItem
import org.koitharu.kotatsu.list.ui.model.ListModel
class MangaCategoriesAdapter(
clickListener: OnListItemClickListener<MangaCategoryItem>,
) : AsyncListDifferDelegationAdapter<ListModel>(DiffCallback()) {
) : BaseListAdapter<ListModel>() {
init {
delegatesManager.addDelegate(mangaCategoryAD(clickListener))
.addDelegate(categoriesHeaderAD())
}
private class DiffCallback : DiffUtil.ItemCallback<ListModel>() {
override fun areItemsTheSame(
oldItem: ListModel,
newItem: ListModel,
): Boolean = when {
oldItem is MangaCategoryItem && newItem is MangaCategoryItem -> oldItem.id == newItem.id
oldItem is CategoriesHeaderItem && newItem is CategoriesHeaderItem -> oldItem == newItem
else -> false
}
override fun areContentsTheSame(
oldItem: ListModel,
newItem: ListModel,
): Boolean = oldItem == newItem
override fun getChangePayload(
oldItem: ListModel,
newItem: ListModel,
): Any? {
if (oldItem is MangaCategoryItem && newItem is MangaCategoryItem && oldItem.isChecked != newItem.isChecked) {
return newItem.isChecked
}
return super.getChangePayload(oldItem, newItem)
}
}
}

View File

@@ -2,8 +2,10 @@ package org.koitharu.kotatsu.favourites.ui.categories.select.adapter
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.core.util.ext.setChecked
import org.koitharu.kotatsu.databinding.ItemCheckableNewBinding
import org.koitharu.kotatsu.favourites.ui.categories.select.model.MangaCategoryItem
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
import org.koitharu.kotatsu.list.ui.model.ListModel
fun mangaCategoryAD(
@@ -16,10 +18,10 @@ fun mangaCategoryAD(
clickListener.onItemClick(item, itemView)
}
bind {
bind { payloads ->
with(binding.root) {
text = item.name
isChecked = item.isChecked
setChecked(item.isChecked, ListModelDiffCallback.PAYLOAD_CHECKED_CHANGED in payloads)
}
}
}

View File

@@ -4,7 +4,6 @@ import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.AdapterListUpdateCallback
import androidx.recyclerview.widget.AsyncDifferConfig
import androidx.recyclerview.widget.AsyncListDiffer
import androidx.recyclerview.widget.DiffUtil
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator.TabConfigurationStrategy
@@ -13,6 +12,7 @@ import kotlinx.coroutines.asExecutor
import kotlinx.coroutines.flow.FlowCollector
import org.koitharu.kotatsu.core.util.ContinuationResumeRunnable
import org.koitharu.kotatsu.favourites.ui.list.FavouritesListFragment
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
import kotlin.coroutines.suspendCoroutine
class FavouritesContainerAdapter(fragment: Fragment) :
@@ -22,7 +22,7 @@ class FavouritesContainerAdapter(fragment: Fragment) :
private val differ = AsyncListDiffer(
AdapterListUpdateCallback(this),
AsyncDifferConfig.Builder(DiffCallback())
AsyncDifferConfig.Builder(ListModelDiffCallback<FavouriteTabModel>())
.setBackgroundThreadExecutor(Dispatchers.Default.limitedParallelism(2).asExecutor())
.build(),
)
@@ -51,15 +51,4 @@ class FavouritesContainerAdapter(fragment: Fragment) :
override suspend fun emit(value: List<FavouriteTabModel>) = suspendCoroutine { cont ->
differ.submitList(value, ContinuationResumeRunnable(cont))
}
private class DiffCallback : DiffUtil.ItemCallback<FavouriteTabModel>() {
override fun areItemsTheSame(oldItem: FavouriteTabModel, newItem: FavouriteTabModel): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: FavouriteTabModel, newItem: FavouriteTabModel): Boolean {
return oldItem == newItem
}
}
}

View File

@@ -4,6 +4,7 @@ import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.plus
import org.koitharu.kotatsu.core.ui.BaseViewModel
@@ -18,5 +19,6 @@ class FavouritesContainerViewModel @Inject constructor(
val categories = favouritesRepository.observeCategories()
.mapItems { FavouriteTabModel(it.id, it.title) }
.distinctUntilChanged()
.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, emptyList())
}

View File

@@ -2,7 +2,7 @@ package org.koitharu.kotatsu.filter.ui
import android.content.Context
import androidx.recyclerview.widget.AsyncListDiffer.ListListener
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
import org.koitharu.kotatsu.core.ui.BaseListAdapter
import org.koitharu.kotatsu.core.ui.list.fastscroll.FastScroller
import org.koitharu.kotatsu.filter.ui.model.FilterItem
import org.koitharu.kotatsu.list.ui.adapter.listHeaderAD
@@ -13,7 +13,7 @@ import org.koitharu.kotatsu.list.ui.model.ListModel
class FilterAdapter(
listener: OnFilterChangedListener,
listListener: ListListener<ListModel>,
) : AsyncListDifferDelegationAdapter<ListModel>(FilterDiffCallback()), FastScroller.SectionIndexer {
) : BaseListAdapter<ListModel>(), FastScroller.SectionIndexer {
init {
delegatesManager.addDelegate(filterSortDelegate(listener)).addDelegate(filterTagDelegate(listener))

View File

@@ -1,52 +0,0 @@
package org.koitharu.kotatsu.filter.ui
import androidx.recyclerview.widget.DiffUtil
import org.koitharu.kotatsu.filter.ui.model.FilterItem
import org.koitharu.kotatsu.list.ui.model.ListHeader
import org.koitharu.kotatsu.list.ui.model.ListModel
class FilterDiffCallback : DiffUtil.ItemCallback<ListModel>() {
override fun areItemsTheSame(oldItem: ListModel, newItem: ListModel): Boolean {
return when {
oldItem === newItem -> true
oldItem.javaClass != newItem.javaClass -> false
oldItem is ListHeader && newItem is ListHeader -> {
oldItem == newItem
}
oldItem is FilterItem.Tag && newItem is FilterItem.Tag -> {
oldItem.tag == newItem.tag
}
oldItem is FilterItem.Sort && newItem is FilterItem.Sort -> {
oldItem.order == newItem.order
}
oldItem is FilterItem.Error && newItem is FilterItem.Error -> {
oldItem.textResId == newItem.textResId
}
else -> false
}
}
override fun areContentsTheSame(oldItem: ListModel, newItem: ListModel): Boolean {
return oldItem == newItem
}
override fun getChangePayload(oldItem: ListModel, newItem: ListModel): Any? {
val hasPayload = when {
oldItem is FilterItem.Tag && newItem is FilterItem.Tag -> {
oldItem.isChecked != newItem.isChecked
}
oldItem is FilterItem.Sort && newItem is FilterItem.Sort -> {
oldItem.isSelected != newItem.isSelected
}
else -> false
}
return if (hasPayload) Unit else super.getChangePayload(oldItem, newItem)
}
}

View File

@@ -31,7 +31,7 @@ class FilterSheetFragment :
addSheetCallback(this)
val adapter = FilterAdapter(filter, this)
binding.recyclerView.adapter = adapter
filter.filterItems.observe(viewLifecycleOwner, adapter::setItems)
filter.filterItems.observe(viewLifecycleOwner, adapter)
if (dialog == null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
binding.recyclerView.scrollIndicators = 0

View File

@@ -3,20 +3,24 @@ package org.koitharu.kotatsu.list.ui
import androidx.recyclerview.widget.DiffUtil
import org.koitharu.kotatsu.list.ui.model.ListModel
object ListModelDiffCallback : DiffUtil.ItemCallback<ListModel>() {
open class ListModelDiffCallback<T : ListModel> : DiffUtil.ItemCallback<T>() {
val PAYLOAD_CHECKED_CHANGED = Any()
val PAYLOAD_NESTED_LIST_CHANGED = Any()
override fun areItemsTheSame(oldItem: ListModel, newItem: ListModel): Boolean {
override fun areItemsTheSame(oldItem: T, newItem: T): Boolean {
return oldItem.areItemsTheSame(newItem)
}
override fun areContentsTheSame(oldItem: ListModel, newItem: ListModel): Boolean {
override fun areContentsTheSame(oldItem: T, newItem: T): Boolean {
return oldItem == newItem
}
override fun getChangePayload(oldItem: ListModel, newItem: ListModel): Any? {
override fun getChangePayload(oldItem: T, newItem: T): Any? {
return newItem.getChangePayload(oldItem)
}
companion object : ListModelDiffCallback<ListModel>() {
val PAYLOAD_CHECKED_CHANGED = Any()
val PAYLOAD_NESTED_LIST_CHANGED = Any()
val PAYLOAD_ANYTHING_CHANGED = Any()
}
}

View File

@@ -3,12 +3,13 @@ package org.koitharu.kotatsu.list.ui.adapter
import androidx.lifecycle.LifecycleOwner
import coil.ImageLoader
import org.koitharu.kotatsu.core.ui.BaseListAdapter
import org.koitharu.kotatsu.list.ui.model.ListModel
open class MangaListAdapter(
coil: ImageLoader,
lifecycleOwner: LifecycleOwner,
listener: MangaListListener,
) : BaseListAdapter() {
) : BaseListAdapter<ListModel>() {
init {
delegatesManager

View File

@@ -3,10 +3,9 @@ package org.koitharu.kotatsu.reader.ui.thumbnails.adapter
import android.content.Context
import androidx.lifecycle.LifecycleOwner
import coil.ImageLoader
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
import org.koitharu.kotatsu.core.ui.BaseListAdapter
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.core.ui.list.fastscroll.FastScroller
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
import org.koitharu.kotatsu.list.ui.adapter.listHeaderAD
import org.koitharu.kotatsu.list.ui.adapter.loadingFooterAD
import org.koitharu.kotatsu.list.ui.model.ListHeader
@@ -17,7 +16,7 @@ class PageThumbnailAdapter(
coil: ImageLoader,
lifecycleOwner: LifecycleOwner,
clickListener: OnListItemClickListener<PageThumbnail>,
) : AsyncListDifferDelegationAdapter<ListModel>(ListModelDiffCallback), FastScroller.SectionIndexer {
) : BaseListAdapter<ListModel>(), FastScroller.SectionIndexer {
init {
delegatesManager.addDelegate(ITEM_TYPE_THUMBNAIL, pageThumbnailAD(coil, lifecycleOwner, clickListener))

View File

@@ -1,48 +1,22 @@
package org.koitharu.kotatsu.scrobbling.common.ui.config.adapter
import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.DiffUtil
import coil.ImageLoader
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
import org.koitharu.kotatsu.core.ui.BaseListAdapter
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.list.ui.adapter.emptyStateListAD
import org.koitharu.kotatsu.list.ui.model.EmptyState
import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingInfo
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingStatus
class ScrobblingMangaAdapter(
clickListener: OnListItemClickListener<ScrobblingInfo>,
coil: ImageLoader,
lifecycleOwner: LifecycleOwner,
) : AsyncListDifferDelegationAdapter<ListModel>(DiffCallback()) {
) : BaseListAdapter<ListModel>() {
init {
delegatesManager.addDelegate(scrobblingMangaAD(clickListener, coil, lifecycleOwner))
.addDelegate(scrobblingHeaderAD())
.addDelegate(emptyStateListAD(coil, lifecycleOwner, null))
}
private class DiffCallback : DiffUtil.ItemCallback<ListModel>() {
override fun areItemsTheSame(oldItem: ListModel, newItem: ListModel): Boolean {
return when {
oldItem is ScrobblingInfo && newItem is ScrobblingInfo -> {
oldItem.targetId == newItem.targetId && oldItem.mangaId == newItem.mangaId
}
oldItem is ScrobblingStatus && newItem is ScrobblingStatus -> {
oldItem.ordinal == newItem.ordinal
}
oldItem is EmptyState && newItem is EmptyState -> true
else -> false
}
}
override fun areContentsTheSame(oldItem: ListModel, newItem: ListModel): Boolean {
return oldItem == newItem
}
}
}

View File

@@ -1,25 +1,21 @@
package org.koitharu.kotatsu.scrobbling.common.ui.selector.adapter
import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.DiffUtil
import coil.ImageLoader
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
import org.koitharu.kotatsu.core.ui.BaseListAdapter
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.list.ui.adapter.ListStateHolderListener
import org.koitharu.kotatsu.list.ui.adapter.loadingFooterAD
import org.koitharu.kotatsu.list.ui.adapter.loadingStateAD
import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.list.ui.model.LoadingFooter
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerManga
import org.koitharu.kotatsu.scrobbling.common.ui.selector.model.ScrobblerHint
import kotlin.jvm.internal.Intrinsics
class ScrobblerSelectorAdapter(
lifecycleOwner: LifecycleOwner,
coil: ImageLoader,
clickListener: OnListItemClickListener<ScrobblerManga>,
stateHolderListener: ListStateHolderListener,
) : AsyncListDifferDelegationAdapter<ListModel>(DiffCallback()) {
) : BaseListAdapter<ListModel>() {
init {
delegatesManager.addDelegate(loadingStateAD())
@@ -27,21 +23,4 @@ class ScrobblerSelectorAdapter(
.addDelegate(loadingFooterAD())
.addDelegate(scrobblerHintAD(stateHolderListener))
}
private class DiffCallback : DiffUtil.ItemCallback<ListModel>() {
override fun areItemsTheSame(oldItem: ListModel, newItem: ListModel): Boolean {
return when {
oldItem === newItem -> true
oldItem is ScrobblerManga && newItem is ScrobblerManga -> oldItem.id == newItem.id
oldItem is ScrobblerHint && newItem is ScrobblerHint -> oldItem.textPrimary == newItem.textPrimary
oldItem is LoadingFooter && newItem is LoadingFooter -> oldItem.key == newItem.key
else -> false
}
}
override fun areContentsTheSame(oldItem: ListModel, newItem: ListModel): Boolean {
return Intrinsics.areEqual(oldItem, newItem)
}
}
}

View File

@@ -1,10 +1,9 @@
package org.koitharu.kotatsu.search.ui.multi.adapter
import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView.RecycledViewPool
import coil.ImageLoader
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
import org.koitharu.kotatsu.core.ui.BaseListAdapter
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.list.ui.MangaSelectionDecoration
import org.koitharu.kotatsu.list.ui.adapter.MangaListListener
@@ -13,10 +12,8 @@ import org.koitharu.kotatsu.list.ui.adapter.errorStateListAD
import org.koitharu.kotatsu.list.ui.adapter.loadingFooterAD
import org.koitharu.kotatsu.list.ui.adapter.loadingStateAD
import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.list.ui.model.LoadingFooter
import org.koitharu.kotatsu.list.ui.size.ItemSizeResolver
import org.koitharu.kotatsu.search.ui.multi.MultiSearchListModel
import kotlin.jvm.internal.Intrinsics
class MultiSearchAdapter(
lifecycleOwner: LifecycleOwner,
@@ -25,7 +22,7 @@ class MultiSearchAdapter(
itemClickListener: OnListItemClickListener<MultiSearchListModel>,
sizeResolver: ItemSizeResolver,
selectionDecoration: MangaSelectionDecoration,
) : AsyncListDifferDelegationAdapter<ListModel>(DiffCallback()) {
) : BaseListAdapter<ListModel>() {
init {
val pool = RecycledViewPool()
@@ -46,25 +43,4 @@ class MultiSearchAdapter(
.addDelegate(emptyStateListAD(coil, lifecycleOwner, listener))
.addDelegate(errorStateListAD(listener))
}
private class DiffCallback : DiffUtil.ItemCallback<ListModel>() {
override fun areItemsTheSame(oldItem: ListModel, newItem: ListModel): Boolean {
return when {
oldItem is MultiSearchListModel && newItem is MultiSearchListModel -> {
oldItem.source == newItem.source
}
oldItem is LoadingFooter && newItem is LoadingFooter -> {
oldItem.key == newItem.key
}
else -> oldItem.javaClass == newItem.javaClass
}
}
override fun areContentsTheSame(oldItem: ListModel, newItem: ListModel): Boolean {
return Intrinsics.areEqual(oldItem, newItem)
}
}
}

View File

@@ -1,12 +1,10 @@
package org.koitharu.kotatsu.search.ui.suggestion.adapter
import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.DiffUtil
import coil.ImageLoader
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
import org.koitharu.kotatsu.core.ui.BaseListAdapter
import org.koitharu.kotatsu.search.ui.suggestion.SearchSuggestionListener
import org.koitharu.kotatsu.search.ui.suggestion.model.SearchSuggestionItem
import kotlin.jvm.internal.Intrinsics
const val SEARCH_SUGGESTION_ITEM_TYPE_QUERY = 0
@@ -14,7 +12,7 @@ class SearchSuggestionAdapter(
coil: ImageLoader,
lifecycleOwner: LifecycleOwner,
listener: SearchSuggestionListener,
) : AsyncListDifferDelegationAdapter<SearchSuggestionItem>(DiffCallback()) {
) : BaseListAdapter<SearchSuggestionItem>() {
init {
delegatesManager
@@ -23,35 +21,4 @@ class SearchSuggestionAdapter(
.addDelegate(searchSuggestionTagsAD(listener))
.addDelegate(searchSuggestionMangaListAD(coil, lifecycleOwner, listener))
}
private class DiffCallback : DiffUtil.ItemCallback<SearchSuggestionItem>() {
override fun areItemsTheSame(
oldItem: SearchSuggestionItem,
newItem: SearchSuggestionItem,
): Boolean = when {
oldItem is SearchSuggestionItem.RecentQuery && newItem is SearchSuggestionItem.RecentQuery -> {
oldItem.query == newItem.query
}
oldItem is SearchSuggestionItem.Source && newItem is SearchSuggestionItem.Source -> {
oldItem.source == newItem.source
}
else -> oldItem.javaClass == newItem.javaClass
}
override fun areContentsTheSame(
oldItem: SearchSuggestionItem,
newItem: SearchSuggestionItem,
): Boolean = Intrinsics.areEqual(oldItem, newItem)
override fun getChangePayload(oldItem: SearchSuggestionItem, newItem: SearchSuggestionItem): Any? {
return when {
oldItem is SearchSuggestionItem.MangaList && newItem is SearchSuggestionItem.MangaList -> Unit
oldItem is SearchSuggestionItem.Source && newItem is SearchSuggestionItem.Source -> {
if (oldItem.isEnabled != newItem.isEnabled) Unit else super.getChangePayload(oldItem, newItem)
}
else -> super.getChangePayload(oldItem, newItem)
}
}
}
}
}

View File

@@ -1,16 +1,22 @@
package org.koitharu.kotatsu.search.ui.suggestion.model
import org.koitharu.kotatsu.core.ui.widgets.ChipsView
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.util.areItemsEquals
sealed interface SearchSuggestionItem {
sealed interface SearchSuggestionItem : ListModel {
class MangaList(
val items: List<Manga>,
) : SearchSuggestionItem {
override fun areItemsTheSame(other: ListModel): Boolean {
return other is MangaList
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
@@ -35,6 +41,10 @@ sealed interface SearchSuggestionItem {
val query: String,
) : SearchSuggestionItem {
override fun areItemsTheSame(other: ListModel): Boolean {
return other is RecentQuery && query == other.query
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
@@ -54,6 +64,21 @@ sealed interface SearchSuggestionItem {
val isEnabled: Boolean,
) : SearchSuggestionItem {
override fun areItemsTheSame(other: ListModel): Boolean {
return other is Source && other.source == source
}
override fun getChangePayload(previousState: ListModel): Any? {
if (previousState !is Source) {
return super.getChangePayload(previousState)
}
return if (isEnabled != previousState.isEnabled) {
ListModelDiffCallback.PAYLOAD_CHECKED_CHANGED
} else {
null
}
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
@@ -75,6 +100,14 @@ sealed interface SearchSuggestionItem {
val tags: List<ChipsView.ChipModel>,
) : SearchSuggestionItem {
override fun areItemsTheSame(other: ListModel): Boolean {
return other is Tags
}
override fun getChangePayload(previousState: ListModel): Any {
return ListModelDiffCallback.PAYLOAD_NESTED_LIST_CHANGED
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false

View File

@@ -2,8 +2,7 @@ package org.koitharu.kotatsu.settings.newsources
import androidx.lifecycle.LifecycleOwner
import coil.ImageLoader
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
import org.koitharu.kotatsu.settings.sources.adapter.SourceConfigDiffCallback
import org.koitharu.kotatsu.core.ui.BaseListAdapter
import org.koitharu.kotatsu.settings.sources.adapter.SourceConfigListener
import org.koitharu.kotatsu.settings.sources.adapter.sourceConfigItemCheckableDelegate
import org.koitharu.kotatsu.settings.sources.model.SourceConfigItem
@@ -12,7 +11,6 @@ class SourcesSelectAdapter(
listener: SourceConfigListener,
coil: ImageLoader,
lifecycleOwner: LifecycleOwner,
) : AsyncListDifferDelegationAdapter<SourceConfigItem>(
SourceConfigDiffCallback(),
) : BaseListAdapter<SourceConfigItem>(
sourceConfigItemCheckableDelegate(listener, coil, lifecycleOwner),
)

View File

@@ -1,27 +1,13 @@
package org.koitharu.kotatsu.settings.onboard.adapter
import androidx.recyclerview.widget.DiffUtil
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
import org.koitharu.kotatsu.core.ui.BaseListAdapter
import org.koitharu.kotatsu.settings.onboard.model.SourceLocale
class SourceLocalesAdapter(
listener: SourceLocaleListener,
) : AsyncListDifferDelegationAdapter<SourceLocale>(DiffCallback()) {
) : BaseListAdapter<SourceLocale>() {
init {
delegatesManager.addDelegate(sourceLocaleAD(listener))
}
private class DiffCallback : DiffUtil.ItemCallback<SourceLocale>() {
override fun areItemsTheSame(
oldItem: SourceLocale,
newItem: SourceLocale,
): Boolean = oldItem.key == newItem.key
override fun areContentsTheSame(
oldItem: SourceLocale,
newItem: SourceLocale,
): Boolean = oldItem == newItem
}
}

View File

@@ -1,5 +1,7 @@
package org.koitharu.kotatsu.settings.onboard.model
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
import org.koitharu.kotatsu.list.ui.model.ListModel
import java.util.Locale
data class SourceLocale(
@@ -7,7 +9,19 @@ data class SourceLocale(
val title: String?,
val summary: String?,
val isChecked: Boolean,
) : Comparable<SourceLocale> {
) : ListModel, Comparable<SourceLocale> {
override fun areItemsTheSame(other: ListModel): Boolean {
return other is SourceLocale && key == other.key
}
override fun getChangePayload(previousState: ListModel): Any? {
return if (previousState is SourceLocale && previousState.isChecked != isChecked) {
ListModelDiffCallback.PAYLOAD_CHECKED_CHANGED
} else {
super.getChangePayload(previousState)
}
}
override fun compareTo(other: SourceLocale): Int {
return when {

View File

@@ -2,15 +2,14 @@ package org.koitharu.kotatsu.settings.sources.adapter
import androidx.lifecycle.LifecycleOwner
import coil.ImageLoader
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
import org.koitharu.kotatsu.core.ui.BaseListAdapter
import org.koitharu.kotatsu.settings.sources.model.SourceConfigItem
class SourceConfigAdapter(
listener: SourceConfigListener,
coil: ImageLoader,
lifecycleOwner: LifecycleOwner,
) : AsyncListDifferDelegationAdapter<SourceConfigItem>(
SourceConfigDiffCallback(),
) : BaseListAdapter<SourceConfigItem>(
sourceConfigHeaderDelegate(),
sourceConfigGroupDelegate(listener),
sourceConfigItemDelegate2(listener, coil, lifecycleOwner),

View File

@@ -1,44 +0,0 @@
package org.koitharu.kotatsu.settings.sources.adapter
import androidx.recyclerview.widget.DiffUtil
import org.koitharu.kotatsu.settings.sources.model.SourceConfigItem
import org.koitharu.kotatsu.settings.sources.model.SourceConfigItem.EmptySearchResult
import org.koitharu.kotatsu.settings.sources.model.SourceConfigItem.Header
import org.koitharu.kotatsu.settings.sources.model.SourceConfigItem.LocaleGroup
import org.koitharu.kotatsu.settings.sources.model.SourceConfigItem.SourceItem
class SourceConfigDiffCallback : DiffUtil.ItemCallback<SourceConfigItem>() {
override fun areItemsTheSame(oldItem: SourceConfigItem, newItem: SourceConfigItem): Boolean {
return when {
oldItem.javaClass != newItem.javaClass -> false
oldItem is LocaleGroup && newItem is LocaleGroup -> {
oldItem.localeId == newItem.localeId
}
oldItem is SourceItem && newItem is SourceItem -> {
oldItem.source == newItem.source
}
oldItem is Header && newItem is Header -> {
oldItem.titleResId == newItem.titleResId
}
oldItem == EmptySearchResult && newItem == EmptySearchResult -> {
true
}
oldItem is SourceConfigItem.Tip && newItem is SourceConfigItem.Tip -> {
oldItem.key == newItem.key
}
else -> false
}
}
override fun areContentsTheSame(oldItem: SourceConfigItem, newItem: SourceConfigItem): Boolean {
return oldItem == newItem
}
override fun getChangePayload(oldItem: SourceConfigItem, newItem: SourceConfigItem) = Unit
}

View File

@@ -2,14 +2,20 @@ package org.koitharu.kotatsu.settings.sources.model
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.parsers.model.MangaSource
sealed interface SourceConfigItem {
sealed interface SourceConfigItem : ListModel {
class Header(
@StringRes val titleResId: Int,
) : SourceConfigItem {
override fun areItemsTheSame(other: ListModel): Boolean {
return other is Header && other.titleResId == titleResId
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
@@ -26,6 +32,18 @@ sealed interface SourceConfigItem {
val isExpanded: Boolean,
) : SourceConfigItem {
override fun areItemsTheSame(other: ListModel): Boolean {
return other is LocaleGroup && other.localeId == localeId
}
override fun getChangePayload(previousState: ListModel): Any? {
return if (previousState is LocaleGroup && previousState.isExpanded != isExpanded) {
ListModelDiffCallback.PAYLOAD_CHECKED_CHANGED
} else {
super.getChangePayload(previousState)
}
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
@@ -54,6 +72,18 @@ sealed interface SourceConfigItem {
val isDraggable: Boolean,
) : SourceConfigItem {
override fun areItemsTheSame(other: ListModel): Boolean {
return other is SourceItem && other.source == source
}
override fun getChangePayload(previousState: ListModel): Any? {
return if (previousState is SourceItem && previousState.isEnabled != isEnabled) {
ListModelDiffCallback.PAYLOAD_CHECKED_CHANGED
} else {
super.getChangePayload(previousState)
}
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
@@ -83,6 +113,10 @@ sealed interface SourceConfigItem {
@StringRes val textResId: Int,
) : SourceConfigItem {
override fun areItemsTheSame(other: ListModel): Boolean {
return other is Tip && other.key == key
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
@@ -104,5 +138,14 @@ sealed interface SourceConfigItem {
}
}
object EmptySearchResult : SourceConfigItem
object EmptySearchResult : SourceConfigItem {
override fun equals(other: Any?): Boolean {
return other === EmptySearchResult
}
override fun areItemsTheSame(other: ListModel): Boolean {
return other is EmptySearchResult
}
}
}

View File

@@ -1,32 +1,11 @@
package org.koitharu.kotatsu.settings.tracker.categories
import androidx.recyclerview.widget.DiffUtil
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
import org.koitharu.kotatsu.core.model.FavouriteCategory
import org.koitharu.kotatsu.core.ui.BaseListAdapter
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
class TrackerCategoriesConfigAdapter(
listener: OnListItemClickListener<FavouriteCategory>,
) : AsyncListDifferDelegationAdapter<FavouriteCategory>(DiffCallback()) {
init {
delegatesManager.addDelegate(trackerCategoryAD(listener))
}
class DiffCallback : DiffUtil.ItemCallback<FavouriteCategory>() {
override fun areItemsTheSame(oldItem: FavouriteCategory, newItem: FavouriteCategory): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: FavouriteCategory, newItem: FavouriteCategory): Boolean {
return oldItem.isTrackingEnabled == newItem.isTrackingEnabled && oldItem.title == newItem.title
}
override fun getChangePayload(oldItem: FavouriteCategory, newItem: FavouriteCategory): Any? {
return if (oldItem.isTrackingEnabled == newItem.isTrackingEnabled) {
super.getChangePayload(oldItem, newItem)
} else Unit
}
}
}
) : BaseListAdapter<FavouriteCategory>(
trackerCategoryAD(listener),
)

View File

@@ -4,11 +4,10 @@ import android.content.Context
import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.RecyclerView
import coil.ImageLoader
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
import org.koitharu.kotatsu.core.ui.BaseListAdapter
import org.koitharu.kotatsu.core.ui.list.NestedScrollStateHandle
import org.koitharu.kotatsu.core.ui.list.SectionedSelectionController
import org.koitharu.kotatsu.core.ui.list.fastscroll.FastScroller
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
import org.koitharu.kotatsu.list.ui.adapter.emptyHintAD
import org.koitharu.kotatsu.list.ui.adapter.emptyStateListAD
import org.koitharu.kotatsu.list.ui.adapter.errorStateListAD
@@ -25,7 +24,7 @@ class ShelfAdapter(
sizeResolver: ItemSizeResolver,
selectionController: SectionedSelectionController<ShelfSectionModel>,
nestedScrollStateHandle: NestedScrollStateHandle,
) : AsyncListDifferDelegationAdapter<ListModel>(ListModelDiffCallback), FastScroller.SectionIndexer {
) : BaseListAdapter<ListModel>(), FastScroller.SectionIndexer {
init {
val pool = RecyclerView.RecycledViewPool()

View File

@@ -1,12 +1,11 @@
package org.koitharu.kotatsu.shelf.ui.config
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
import org.koitharu.kotatsu.core.ui.BaseListAdapter
import org.koitharu.kotatsu.list.ui.model.ListModel
class ShelfSettingsAdapter(
listener: ShelfSettingsListener,
) : AsyncListDifferDelegationAdapter<ListModel>(ListModelDiffCallback) {
) : BaseListAdapter<ListModel>() {
init {
delegatesManager.addDelegate(shelfCategoryAD(listener))

View File

@@ -3,9 +3,8 @@ package org.koitharu.kotatsu.tracker.ui.feed.adapter
import android.content.Context
import androidx.lifecycle.LifecycleOwner
import coil.ImageLoader
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
import org.koitharu.kotatsu.core.ui.BaseListAdapter
import org.koitharu.kotatsu.core.ui.list.fastscroll.FastScroller
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
import org.koitharu.kotatsu.list.ui.adapter.MangaListListener
import org.koitharu.kotatsu.list.ui.adapter.emptyStateListAD
import org.koitharu.kotatsu.list.ui.adapter.errorFooterAD
@@ -20,7 +19,7 @@ class FeedAdapter(
coil: ImageLoader,
lifecycleOwner: LifecycleOwner,
listener: MangaListListener,
) : AsyncListDifferDelegationAdapter<ListModel>(ListModelDiffCallback), FastScroller.SectionIndexer {
) : BaseListAdapter<ListModel>(), FastScroller.SectionIndexer {
init {
delegatesManager.addDelegate(ITEM_TYPE_FEED, feedItemAD(coil, lifecycleOwner, listener))
@@ -52,6 +51,5 @@ class FeedAdapter(
const val ITEM_TYPE_ERROR_FOOTER = 4
const val ITEM_TYPE_EMPTY = 5
const val ITEM_TYPE_HEADER = 6
const val ITEM_TYPE_DATE_HEADER = 7
}
}

View File

@@ -1,33 +1,14 @@
package org.koitharu.kotatsu.widget.shelf.adapter
import androidx.recyclerview.widget.DiffUtil
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
import org.koitharu.kotatsu.core.ui.BaseListAdapter
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.widget.shelf.model.CategoryItem
class CategorySelectAdapter(
clickListener: OnListItemClickListener<CategoryItem>
) : AsyncListDifferDelegationAdapter<CategoryItem>(DiffCallback()) {
) : BaseListAdapter<CategoryItem>() {
init {
delegatesManager.addDelegate(categorySelectItemAD(clickListener))
}
private class DiffCallback : DiffUtil.ItemCallback<CategoryItem>() {
override fun areItemsTheSame(oldItem: CategoryItem, newItem: CategoryItem): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: CategoryItem, newItem: CategoryItem): Boolean {
return oldItem == newItem
}
override fun getChangePayload(oldItem: CategoryItem, newItem: CategoryItem): Any? {
if (oldItem.isSelected != newItem.isSelected) {
return newItem.isSelected
}
return super.getChangePayload(oldItem, newItem)
}
}
}

View File

@@ -1,7 +1,23 @@
package org.koitharu.kotatsu.widget.shelf.model
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
import org.koitharu.kotatsu.list.ui.model.ListModel
data class CategoryItem(
val id: Long,
val name: String?,
val isSelected: Boolean
)
) : ListModel {
override fun areItemsTheSame(other: ListModel): Boolean {
return other is CategoryItem && other.id == id
}
override fun getChangePayload(previousState: ListModel): Any? {
return if (previousState is CategoryItem && previousState.isSelected != isSelected) {
ListModelDiffCallback.PAYLOAD_CHECKED_CHANGED
} else {
null
}
}
}

View File

@@ -74,6 +74,7 @@
</style>
<style name="Widget.Kotatsu.Tabs" parent="@style/Widget.Material3.TabLayout">
<item name="android:background">?colorOutline</item>
<item name="tabBackground">@drawable/tabs_background</item>
<item name="tabGravity">center</item>
<item name="tabInlineLabel">true</item>