Update bookmarks list screen
This commit is contained in:
@@ -12,9 +12,12 @@ import org.koitharu.kotatsu.core.db.entity.MangaWithTags
|
||||
@Dao
|
||||
abstract class BookmarksDao {
|
||||
|
||||
@Query("SELECT * FROM bookmarks WHERE manga_id = :mangaId AND page_id = :pageId ORDER BY percent")
|
||||
@Query("SELECT * FROM bookmarks WHERE manga_id = :mangaId AND page_id = :pageId")
|
||||
abstract suspend fun find(mangaId: Long, pageId: Long): BookmarkEntity?
|
||||
|
||||
@Query("SELECT * FROM bookmarks WHERE page_id = :pageId")
|
||||
abstract suspend fun find(pageId: Long): BookmarkEntity?
|
||||
|
||||
@Transaction
|
||||
@Query(
|
||||
"SELECT * FROM manga JOIN bookmarks ON bookmarks.manga_id = manga.manga_id ORDER BY percent",
|
||||
@@ -42,6 +45,9 @@ abstract class BookmarksDao {
|
||||
@Query("DELETE FROM bookmarks WHERE manga_id = :mangaId AND page_id = :pageId")
|
||||
abstract suspend fun delete(mangaId: Long, pageId: Long): Int
|
||||
|
||||
@Query("DELETE FROM bookmarks WHERE page_id = :pageId")
|
||||
abstract suspend fun delete(pageId: Long): Int
|
||||
|
||||
@Query("DELETE FROM bookmarks WHERE manga_id = :mangaId AND chapter_id = :chapterId AND page = :page")
|
||||
abstract suspend fun delete(mangaId: Long, chapterId: Long, page: Int): Int
|
||||
|
||||
|
||||
@@ -62,18 +62,16 @@ class BookmarksRepository @Inject constructor(
|
||||
removeBookmark(bookmark.manga.id, bookmark.chapterId, bookmark.page)
|
||||
}
|
||||
|
||||
suspend fun removeBookmarks(ids: Map<Manga, Set<Long>>): ReversibleHandle {
|
||||
suspend fun removeBookmarks(ids: Set<Long>): ReversibleHandle {
|
||||
val entities = ArrayList<BookmarkEntity>(ids.size)
|
||||
db.withTransaction {
|
||||
val dao = db.bookmarksDao
|
||||
for ((manga, idSet) in ids) {
|
||||
for (pageId in idSet) {
|
||||
val e = dao.find(manga.id, pageId)
|
||||
if (e != null) {
|
||||
entities.add(e)
|
||||
}
|
||||
dao.delete(manga.id, pageId)
|
||||
for (pageId in ids) {
|
||||
val e = dao.find(pageId)
|
||||
if (e != null) {
|
||||
entities.add(e)
|
||||
}
|
||||
dao.delete(pageId)
|
||||
}
|
||||
}
|
||||
return BookmarksRestorer(entities)
|
||||
|
||||
@@ -12,31 +12,32 @@ import androidx.core.graphics.Insets
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import coil.ImageLoader
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.bookmarks.data.ids
|
||||
import org.koitharu.kotatsu.bookmarks.domain.Bookmark
|
||||
import org.koitharu.kotatsu.bookmarks.ui.adapter.BookmarksGroupAdapter
|
||||
import org.koitharu.kotatsu.bookmarks.ui.model.BookmarksGroup
|
||||
import org.koitharu.kotatsu.bookmarks.ui.sheet.BookmarksAdapter
|
||||
import org.koitharu.kotatsu.core.exceptions.resolve.SnackbarErrorObserver
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.core.ui.BaseFragment
|
||||
import org.koitharu.kotatsu.core.ui.list.ListSelectionController
|
||||
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.core.ui.list.SectionedSelectionController
|
||||
import org.koitharu.kotatsu.core.ui.list.decor.AbstractSelectionItemDecoration
|
||||
import org.koitharu.kotatsu.core.ui.list.decor.SpacingItemDecoration
|
||||
import org.koitharu.kotatsu.core.ui.list.fastscroll.FastScroller
|
||||
import org.koitharu.kotatsu.core.ui.util.ReversibleAction
|
||||
import org.koitharu.kotatsu.core.ui.util.reverseAsync
|
||||
import org.koitharu.kotatsu.core.util.ext.invalidateNestedItemDecorations
|
||||
import org.koitharu.kotatsu.core.util.ext.observe
|
||||
import org.koitharu.kotatsu.core.util.ext.observeEvent
|
||||
import org.koitharu.kotatsu.core.util.ext.scaleUpActivityOptionsOf
|
||||
import org.koitharu.kotatsu.databinding.FragmentListSimpleBinding
|
||||
import org.koitharu.kotatsu.details.ui.DetailsActivity
|
||||
import org.koitharu.kotatsu.list.ui.MangaListSpanResolver
|
||||
import org.koitharu.kotatsu.list.ui.adapter.ListHeaderClickListener
|
||||
import org.koitharu.kotatsu.list.ui.adapter.ListItemType
|
||||
import org.koitharu.kotatsu.list.ui.adapter.ListStateHolderListener
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
import org.koitharu.kotatsu.list.ui.adapter.TypedListSpacingDecoration
|
||||
import org.koitharu.kotatsu.list.ui.model.ListHeader
|
||||
import org.koitharu.kotatsu.main.ui.owners.AppBarOwner
|
||||
import org.koitharu.kotatsu.main.ui.owners.SnackbarOwner
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
@@ -48,15 +49,18 @@ class BookmarksFragment :
|
||||
BaseFragment<FragmentListSimpleBinding>(),
|
||||
ListStateHolderListener,
|
||||
OnListItemClickListener<Bookmark>,
|
||||
SectionedSelectionController.Callback<Manga>,
|
||||
FastScroller.FastScrollListener {
|
||||
ListSelectionController.Callback2,
|
||||
FastScroller.FastScrollListener, ListHeaderClickListener {
|
||||
|
||||
@Inject
|
||||
lateinit var coil: ImageLoader
|
||||
|
||||
@Inject
|
||||
lateinit var settings: AppSettings
|
||||
|
||||
private val viewModel by viewModels<BookmarksViewModel>()
|
||||
private var adapter: BookmarksGroupAdapter? = null
|
||||
private var selectionController: SectionedSelectionController<Manga>? = null
|
||||
private var bookmarksAdapter: BookmarksAdapter? = null
|
||||
private var selectionController: ListSelectionController? = null
|
||||
|
||||
override fun onCreateViewBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentListSimpleBinding {
|
||||
return FragmentListSimpleBinding.inflate(inflater, container, false)
|
||||
@@ -64,37 +68,46 @@ class BookmarksFragment :
|
||||
|
||||
override fun onViewBindingCreated(binding: FragmentListSimpleBinding, savedInstanceState: Bundle?) {
|
||||
super.onViewBindingCreated(binding, savedInstanceState)
|
||||
selectionController = SectionedSelectionController(
|
||||
selectionController = ListSelectionController(
|
||||
activity = requireActivity(),
|
||||
owner = this,
|
||||
decoration = BookmarksSelectionDecoration(binding.root.context),
|
||||
registryOwner = this,
|
||||
callback = this,
|
||||
)
|
||||
adapter = BookmarksGroupAdapter(
|
||||
bookmarksAdapter = BookmarksAdapter(
|
||||
lifecycleOwner = viewLifecycleOwner,
|
||||
coil = coil,
|
||||
listener = this,
|
||||
selectionController = checkNotNull(selectionController),
|
||||
bookmarkClickListener = this,
|
||||
groupClickListener = OnGroupClickListener(),
|
||||
clickListener = this,
|
||||
headerClickListener = this,
|
||||
)
|
||||
binding.recyclerView.adapter = adapter
|
||||
binding.recyclerView.setHasFixedSize(true)
|
||||
val spacingDecoration = SpacingItemDecoration(resources.getDimensionPixelOffset(R.dimen.grid_spacing))
|
||||
binding.recyclerView.addItemDecoration(spacingDecoration)
|
||||
|
||||
viewModel.content.observe(viewLifecycleOwner, ::onListChanged)
|
||||
val spanSizeLookup = SpanSizeLookup()
|
||||
with(binding.recyclerView) {
|
||||
setHasFixedSize(true)
|
||||
val spanResolver = MangaListSpanResolver(resources)
|
||||
addItemDecoration(TypedListSpacingDecoration(context))
|
||||
adapter = bookmarksAdapter
|
||||
addOnLayoutChangeListener(spanResolver)
|
||||
spanResolver.setGridSize(settings.gridSize / 100f, this)
|
||||
val lm = GridLayoutManager(context, spanResolver.spanCount)
|
||||
lm.spanSizeLookup = spanSizeLookup
|
||||
layoutManager = lm
|
||||
selectionController?.attachToRecyclerView(this)
|
||||
}
|
||||
viewModel.content.observe(viewLifecycleOwner) {
|
||||
bookmarksAdapter?.setItems(it, spanSizeLookup)
|
||||
}
|
||||
viewModel.onError.observeEvent(viewLifecycleOwner, SnackbarErrorObserver(binding.recyclerView, this))
|
||||
viewModel.onActionDone.observeEvent(viewLifecycleOwner, ::onActionDone)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
adapter = null
|
||||
bookmarksAdapter = null
|
||||
selectionController = null
|
||||
}
|
||||
|
||||
override fun onItemClick(item: Bookmark, view: View) {
|
||||
if (selectionController?.onItemClick(item.manga, item.pageId) != true) {
|
||||
if (selectionController?.onItemClick(item.pageId) != true) {
|
||||
val intent = ReaderActivity.IntentBuilder(view.context)
|
||||
.bookmark(item)
|
||||
.incognito(true)
|
||||
@@ -104,8 +117,13 @@ class BookmarksFragment :
|
||||
}
|
||||
}
|
||||
|
||||
override fun onListHeaderClick(item: ListHeader, view: View) {
|
||||
val manga = item.payload as? Manga ?: return
|
||||
startActivity(DetailsActivity.newIntent(view.context, manga))
|
||||
}
|
||||
|
||||
override fun onItemLongClick(item: Bookmark, view: View): Boolean {
|
||||
return selectionController?.onItemLongClick(item.manga, item.pageId) ?: false
|
||||
return selectionController?.onItemLongClick(item.pageId) ?: false
|
||||
}
|
||||
|
||||
override fun onRetryClick(error: Throwable) = Unit
|
||||
@@ -118,24 +136,16 @@ class BookmarksFragment :
|
||||
|
||||
override fun onFastScrollStop(fastScroller: FastScroller) = Unit
|
||||
|
||||
override fun onSelectionChanged(controller: SectionedSelectionController<Manga>, count: Int) {
|
||||
requireViewBinding().recyclerView.invalidateNestedItemDecorations()
|
||||
override fun onSelectionChanged(controller: ListSelectionController, count: Int) {
|
||||
requireViewBinding().recyclerView.invalidateItemDecorations()
|
||||
}
|
||||
|
||||
override fun onCreateActionMode(
|
||||
controller: SectionedSelectionController<Manga>,
|
||||
mode: ActionMode,
|
||||
menu: Menu,
|
||||
): Boolean {
|
||||
override fun onCreateActionMode(controller: ListSelectionController, mode: ActionMode, menu: Menu): Boolean {
|
||||
mode.menuInflater.inflate(R.menu.mode_bookmarks, menu)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onActionItemClicked(
|
||||
controller: SectionedSelectionController<Manga>,
|
||||
mode: ActionMode,
|
||||
item: MenuItem,
|
||||
): Boolean {
|
||||
override fun onActionItemClicked(controller: ListSelectionController, mode: ActionMode, item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.action_remove -> {
|
||||
val ids = selectionController?.snapshot() ?: return false
|
||||
@@ -148,11 +158,6 @@ class BookmarksFragment :
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateItemDecoration(
|
||||
controller: SectionedSelectionController<Manga>,
|
||||
section: Manga,
|
||||
): AbstractSelectionItemDecoration = BookmarksSelectionDecoration(requireContext())
|
||||
|
||||
override fun onWindowInsetsChanged(insets: Insets) {
|
||||
requireViewBinding().recyclerView.updatePadding(
|
||||
bottom = insets.bottom,
|
||||
@@ -162,10 +167,6 @@ class BookmarksFragment :
|
||||
}
|
||||
}
|
||||
|
||||
private fun onListChanged(list: List<ListModel>) {
|
||||
adapter?.items = list
|
||||
}
|
||||
|
||||
private fun onActionDone(action: ReversibleAction) {
|
||||
val handle = action.handle
|
||||
val length = if (handle == null) Snackbar.LENGTH_SHORT else Snackbar.LENGTH_LONG
|
||||
@@ -176,24 +177,24 @@ class BookmarksFragment :
|
||||
snackbar.show()
|
||||
}
|
||||
|
||||
private inner class OnGroupClickListener : OnListItemClickListener<BookmarksGroup> {
|
||||
private inner class SpanSizeLookup : GridLayoutManager.SpanSizeLookup(), Runnable {
|
||||
|
||||
override fun onItemClick(item: BookmarksGroup, view: View) {
|
||||
val controller = selectionController
|
||||
if (controller != null && controller.count > 0) {
|
||||
if (controller.getSectionCount(item.manga) == item.bookmarks.size) {
|
||||
controller.clearSelection(item.manga)
|
||||
} else {
|
||||
controller.addToSelection(item.manga, item.bookmarks.ids())
|
||||
}
|
||||
return
|
||||
}
|
||||
val intent = DetailsActivity.newIntent(view.context, item.manga)
|
||||
startActivity(intent)
|
||||
init {
|
||||
isSpanIndexCacheEnabled = true
|
||||
isSpanGroupIndexCacheEnabled = true
|
||||
}
|
||||
|
||||
override fun onItemLongClick(item: BookmarksGroup, view: View): Boolean {
|
||||
return selectionController?.addToSelection(item.manga, item.bookmarks.ids()) ?: false
|
||||
override fun getSpanSize(position: Int): Int {
|
||||
val total = (viewBinding?.recyclerView?.layoutManager as? GridLayoutManager)?.spanCount ?: return 1
|
||||
return when (bookmarksAdapter?.getItemViewType(position)) {
|
||||
ListItemType.PAGE_THUMB.ordinal -> 1
|
||||
else -> total
|
||||
}
|
||||
}
|
||||
|
||||
override fun run() {
|
||||
invalidateSpanGroupIndexCache()
|
||||
invalidateSpanIndexCache()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,13 +10,14 @@ import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.plus
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.bookmarks.domain.Bookmark
|
||||
import org.koitharu.kotatsu.bookmarks.domain.BookmarksRepository
|
||||
import org.koitharu.kotatsu.bookmarks.ui.model.BookmarksGroup
|
||||
import org.koitharu.kotatsu.core.ui.BaseViewModel
|
||||
import org.koitharu.kotatsu.core.ui.util.ReversibleAction
|
||||
import org.koitharu.kotatsu.core.util.ext.MutableEventFlow
|
||||
import org.koitharu.kotatsu.core.util.ext.call
|
||||
import org.koitharu.kotatsu.list.ui.model.EmptyState
|
||||
import org.koitharu.kotatsu.list.ui.model.ListHeader
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
import org.koitharu.kotatsu.list.ui.model.LoadingState
|
||||
import org.koitharu.kotatsu.list.ui.model.toErrorState
|
||||
@@ -41,17 +42,26 @@ class BookmarksViewModel @Inject constructor(
|
||||
actionStringRes = 0,
|
||||
),
|
||||
)
|
||||
} else list.map { (manga, bookmarks) ->
|
||||
BookmarksGroup(manga, bookmarks)
|
||||
} else {
|
||||
mapList(list)
|
||||
}
|
||||
}
|
||||
.catch { e -> emit(listOf(e.toErrorState(canRetry = false))) }
|
||||
.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, listOf(LoadingState))
|
||||
|
||||
fun removeBookmarks(ids: Map<Manga, Set<Long>>) {
|
||||
fun removeBookmarks(ids: Set<Long>) {
|
||||
launchJob(Dispatchers.Default) {
|
||||
val handle = repository.removeBookmarks(ids)
|
||||
onActionDone.call(ReversibleAction(R.string.bookmarks_removed, handle))
|
||||
}
|
||||
}
|
||||
|
||||
private fun mapList(data: Map<Manga, List<Bookmark>>): List<ListModel> {
|
||||
val result = ArrayList<ListModel>(data.values.sumOf { it.size + 1 })
|
||||
for ((manga, bookmarks) in data) {
|
||||
result.add(ListHeader(manga.title, R.string.more, manga))
|
||||
result.addAll(bookmarks)
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
package org.koitharu.kotatsu.bookmarks.ui.adapter
|
||||
|
||||
import android.view.View
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import coil.ImageLoader
|
||||
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.bookmarks.domain.Bookmark
|
||||
import org.koitharu.kotatsu.bookmarks.ui.model.BookmarksGroup
|
||||
import org.koitharu.kotatsu.core.ui.image.CoverSizeResolver
|
||||
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.core.ui.list.SectionedSelectionController
|
||||
import org.koitharu.kotatsu.core.ui.list.decor.SpacingItemDecoration
|
||||
import org.koitharu.kotatsu.core.util.ext.clearItemDecorations
|
||||
import org.koitharu.kotatsu.core.util.ext.disposeImageRequest
|
||||
import org.koitharu.kotatsu.core.util.ext.enqueueWith
|
||||
import org.koitharu.kotatsu.core.util.ext.newImageRequest
|
||||
import org.koitharu.kotatsu.core.util.ext.source
|
||||
import org.koitharu.kotatsu.databinding.ItemBookmarksGroupBinding
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
|
||||
fun bookmarksGroupAD(
|
||||
coil: ImageLoader,
|
||||
lifecycleOwner: LifecycleOwner,
|
||||
sharedPool: RecyclerView.RecycledViewPool,
|
||||
selectionController: SectionedSelectionController<Manga>,
|
||||
bookmarkClickListener: OnListItemClickListener<Bookmark>,
|
||||
groupClickListener: OnListItemClickListener<BookmarksGroup>,
|
||||
) = adapterDelegateViewBinding<BookmarksGroup, ListModel, ItemBookmarksGroupBinding>(
|
||||
{ layoutInflater, parent -> ItemBookmarksGroupBinding.inflate(layoutInflater, parent, false) },
|
||||
) {
|
||||
val viewListenerAdapter = object : View.OnClickListener, View.OnLongClickListener {
|
||||
override fun onClick(v: View) = groupClickListener.onItemClick(item, v)
|
||||
override fun onLongClick(v: View) = groupClickListener.onItemLongClick(item, v)
|
||||
}
|
||||
|
||||
val adapter = BookmarksAdapter(coil, lifecycleOwner, bookmarkClickListener)
|
||||
binding.recyclerView.setRecycledViewPool(sharedPool)
|
||||
binding.recyclerView.adapter = adapter
|
||||
val spacingDecoration = SpacingItemDecoration(context.resources.getDimensionPixelOffset(R.dimen.grid_spacing))
|
||||
binding.recyclerView.addItemDecoration(spacingDecoration)
|
||||
binding.root.setOnClickListener(viewListenerAdapter)
|
||||
binding.root.setOnLongClickListener(viewListenerAdapter)
|
||||
|
||||
bind { payloads ->
|
||||
if (payloads.isEmpty()) {
|
||||
binding.recyclerView.clearItemDecorations()
|
||||
binding.recyclerView.addItemDecoration(spacingDecoration)
|
||||
selectionController.attachToRecyclerView(item.manga, binding.recyclerView)
|
||||
}
|
||||
binding.imageViewCover.newImageRequest(lifecycleOwner, item.manga.coverUrl)?.run {
|
||||
placeholder(R.drawable.ic_placeholder)
|
||||
fallback(R.drawable.ic_placeholder)
|
||||
error(R.drawable.ic_error_placeholder)
|
||||
allowRgb565(true)
|
||||
size(CoverSizeResolver(binding.imageViewCover))
|
||||
source(item.manga.source)
|
||||
enqueueWith(coil)
|
||||
}
|
||||
binding.textViewTitle.text = item.manga.title
|
||||
adapter.items = item.bookmarks
|
||||
}
|
||||
|
||||
onViewRecycled {
|
||||
binding.imageViewCover.disposeImageRequest()
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package org.koitharu.kotatsu.bookmarks.ui.adapter
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import coil.ImageLoader
|
||||
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.adapter.ListStateHolderListener
|
||||
import org.koitharu.kotatsu.list.ui.adapter.emptyStateListAD
|
||||
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.parsers.model.Manga
|
||||
|
||||
class BookmarksGroupAdapter(
|
||||
coil: ImageLoader,
|
||||
lifecycleOwner: LifecycleOwner,
|
||||
selectionController: SectionedSelectionController<Manga>,
|
||||
listener: ListStateHolderListener,
|
||||
bookmarkClickListener: OnListItemClickListener<Bookmark>,
|
||||
groupClickListener: OnListItemClickListener<BookmarksGroup>,
|
||||
) : BaseListAdapter<ListModel>() {
|
||||
|
||||
init {
|
||||
val pool = RecyclerView.RecycledViewPool()
|
||||
delegatesManager
|
||||
.addDelegate(
|
||||
bookmarksGroupAD(
|
||||
coil = coil,
|
||||
lifecycleOwner = lifecycleOwner,
|
||||
sharedPool = pool,
|
||||
selectionController = selectionController,
|
||||
bookmarkClickListener = bookmarkClickListener,
|
||||
groupClickListener = groupClickListener,
|
||||
),
|
||||
)
|
||||
.addDelegate(loadingStateAD())
|
||||
.addDelegate(loadingFooterAD())
|
||||
.addDelegate(emptyStateListAD(coil, lifecycleOwner, listener))
|
||||
.addDelegate(errorStateListAD(listener))
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package org.koitharu.kotatsu.bookmarks.ui.model
|
||||
|
||||
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
|
||||
|
||||
class BookmarksGroup(
|
||||
val manga: Manga,
|
||||
val bookmarks: List<Bookmark>,
|
||||
) : ListModel {
|
||||
|
||||
override fun areItemsTheSame(other: ListModel): Boolean {
|
||||
return other is BookmarksGroup && other.manga.id == manga.id
|
||||
}
|
||||
|
||||
override fun getChangePayload(previousState: ListModel): Any? {
|
||||
return if (previousState is BookmarksGroup && previousState.bookmarks != bookmarks) {
|
||||
ListModelDiffCallback.PAYLOAD_NESTED_LIST_CHANGED
|
||||
} else {
|
||||
super.getChangePayload(previousState)
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as BookmarksGroup
|
||||
|
||||
if (manga != other.manga) return false
|
||||
|
||||
return bookmarks == other.bookmarks
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = manga.hashCode()
|
||||
result = 31 * result + bookmarks.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -7,9 +7,11 @@ import org.koitharu.kotatsu.bookmarks.domain.Bookmark
|
||||
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.adapter.ListHeaderClickListener
|
||||
import org.koitharu.kotatsu.list.ui.adapter.ListItemType
|
||||
import org.koitharu.kotatsu.list.ui.adapter.listHeaderAD
|
||||
import org.koitharu.kotatsu.list.ui.adapter.loadingFooterAD
|
||||
import org.koitharu.kotatsu.list.ui.adapter.loadingStateAD
|
||||
import org.koitharu.kotatsu.list.ui.model.ListHeader
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
|
||||
@@ -17,12 +19,14 @@ class BookmarksAdapter(
|
||||
coil: ImageLoader,
|
||||
lifecycleOwner: LifecycleOwner,
|
||||
clickListener: OnListItemClickListener<Bookmark>,
|
||||
headerClickListener: ListHeaderClickListener?,
|
||||
) : BaseListAdapter<ListModel>(), FastScroller.SectionIndexer {
|
||||
|
||||
init {
|
||||
addDelegate(ListItemType.PAGE_THUMB, bookmarkLargeAD(coil, lifecycleOwner, clickListener))
|
||||
addDelegate(ListItemType.HEADER, listHeaderAD(null))
|
||||
addDelegate(ListItemType.HEADER, listHeaderAD(headerClickListener))
|
||||
addDelegate(ListItemType.FOOTER_LOADING, loadingFooterAD())
|
||||
addDelegate(ListItemType.STATE_LOADING, loadingStateAD())
|
||||
}
|
||||
|
||||
override fun getSectionText(context: Context, position: Int): CharSequence? {
|
||||
|
||||
@@ -72,6 +72,7 @@ class BookmarksSheet :
|
||||
coil = coil,
|
||||
lifecycleOwner = viewLifecycleOwner,
|
||||
clickListener = this@BookmarksSheet,
|
||||
headerClickListener = null,
|
||||
)
|
||||
viewBinding?.headerBar?.setTitle(R.string.bookmarks)
|
||||
with(binding.recyclerView) {
|
||||
|
||||
@@ -26,8 +26,9 @@ open class BaseListAdapter<T : ListModel>(
|
||||
setItems(value, ContinuationResumeRunnable(cont))
|
||||
}
|
||||
|
||||
fun addDelegate(type: ListItemType, delegate: AdapterDelegate<List<T>>) {
|
||||
fun addDelegate(type: ListItemType, delegate: AdapterDelegate<List<T>>): BaseListAdapter<T> {
|
||||
delegatesManager.addDelegate(type.ordinal, delegate)
|
||||
return this
|
||||
}
|
||||
|
||||
fun addListListener(listListener: ListListener<T>) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.koitharu.kotatsu.details.ui.model
|
||||
|
||||
import org.koitharu.kotatsu.bookmarks.ui.model.BookmarksGroup
|
||||
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.koitharu.kotatsu.search.ui.multi
|
||||
|
||||
import org.koitharu.kotatsu.bookmarks.ui.model.BookmarksGroup
|
||||
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
import org.koitharu.kotatsu.list.ui.model.MangaItemModel
|
||||
|
||||
Reference in New Issue
Block a user