Refactor adapters
This commit is contained in:
@@ -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 }
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)),
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user