Introduce BaseListAdapter and BaseViewHolder
This commit is contained in:
1 parent
4175816577
commit
a6a2a6ebba
7 files changed
+167
-115
No files matched your search
@@ -20,7 +20,7 @@ import com.hippo.widget.LoadImageView
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
class GalleryPreview(
|
||||
data class GalleryPreview(
|
||||
private val imageUrl: String,
|
||||
val pageUrl: String,
|
||||
val position: Int,
|
||||
|
||||
@@ -59,6 +59,7 @@ import com.hippo.ehviewer.AppConfig
|
||||
import com.hippo.ehviewer.R
|
||||
import com.hippo.ehviewer.Settings
|
||||
import com.hippo.ehviewer.client.EhUtils
|
||||
import com.hippo.ehviewer.client.data.GalleryInfo
|
||||
import com.hippo.ehviewer.client.data.ListUrlBuilder
|
||||
import com.hippo.ehviewer.client.parser.GalleryDetailUrlParser
|
||||
import com.hippo.ehviewer.client.parser.GalleryListUrlParser
|
||||
@@ -77,6 +78,7 @@ import com.hippo.util.getClipboardManager
|
||||
import com.hippo.util.getParcelableExtraCompat
|
||||
import com.hippo.util.getUrlFromClipboard
|
||||
import com.hippo.yorozuya.IOUtils
|
||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||
import eu.kanade.tachiyomi.util.lang.launchUI
|
||||
import eu.kanade.tachiyomi.util.lang.withUIContext
|
||||
import kotlinx.coroutines.delay
|
||||
@@ -110,6 +112,14 @@ class MainActivity : EhActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
fun startReaderActivity(galleryInfo: GalleryInfo, page: Int) {
|
||||
val intent = Intent(this, ReaderActivity::class.java)
|
||||
intent.action = ReaderActivity.ACTION_EH
|
||||
intent.putExtra(ReaderActivity.KEY_GALLERY_INFO, galleryInfo)
|
||||
intent.putExtra(ReaderActivity.KEY_PAGE, page)
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
override fun onNewIntent(intent: Intent?) {
|
||||
super.onNewIntent(intent)
|
||||
lifecycleScope.launchUI {
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.hippo.ehviewer.ui.scene
|
||||
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
|
||||
abstract class BaseListAdapter<T>(diffCallback: DiffUtil.ItemCallback<T>) :
|
||||
ListAdapter<T, BaseViewHolder<T>>(diffCallback) {
|
||||
override fun onBindViewHolder(holder: BaseViewHolder<T>, position: Int) {
|
||||
val item = getItem(position)
|
||||
holder.bind(item)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.hippo.ehviewer.ui.scene
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewbinding.ViewBinding
|
||||
|
||||
abstract class BaseViewHolder<T>(binding: ViewBinding, onClick: (T) -> Unit) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
protected var currentItem: T? = null
|
||||
|
||||
init {
|
||||
itemView.setOnClickListener {
|
||||
currentItem?.let { onClick(it) }
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun bind(item: T)
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.hippo.ehviewer.ui.scene
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import com.hippo.ehviewer.client.data.GalleryPreview
|
||||
import com.hippo.ehviewer.databinding.ItemGalleryPreviewBinding
|
||||
|
||||
class GalleryPreviewsAdapter(private val onClick: (GalleryPreview) -> Unit) :
|
||||
BaseListAdapter<GalleryPreview>(PreviewDiffCallback) {
|
||||
class GalleryPreviewHolder(
|
||||
private val binding: ItemGalleryPreviewBinding,
|
||||
onClick: (GalleryPreview) -> Unit
|
||||
) : BaseViewHolder<GalleryPreview>(binding, onClick) {
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun bind(item: GalleryPreview) {
|
||||
currentItem = item
|
||||
item.load(binding.image)
|
||||
binding.text.text = (item.position + 1).toString()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(
|
||||
parent: ViewGroup,
|
||||
viewType: Int
|
||||
): BaseViewHolder<GalleryPreview> {
|
||||
val inflater = LayoutInflater.from(parent.context)
|
||||
val binding = ItemGalleryPreviewBinding.inflate(inflater, parent, false)
|
||||
return GalleryPreviewHolder(binding, onClick)
|
||||
}
|
||||
|
||||
override fun getItemId(position: Int): Long {
|
||||
return getItem(position).position.toLong()
|
||||
}
|
||||
}
|
||||
|
||||
object PreviewDiffCallback : DiffUtil.ItemCallback<GalleryPreview>() {
|
||||
override fun areItemsTheSame(oldItem: GalleryPreview, newItem: GalleryPreview): Boolean {
|
||||
return oldItem.position == newItem.position
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: GalleryPreview, newItem: GalleryPreview): Boolean {
|
||||
return oldItem == newItem
|
||||
}
|
||||
}
|
||||
@@ -15,15 +15,12 @@
|
||||
*/
|
||||
package com.hippo.ehviewer.ui.scene
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.hippo.app.BaseDialogBuilder
|
||||
import com.hippo.easyrecyclerview.MarginItemDecoration
|
||||
import com.hippo.ehviewer.R
|
||||
@@ -35,13 +32,11 @@ import com.hippo.ehviewer.client.data.GalleryDetail
|
||||
import com.hippo.ehviewer.client.data.GalleryPreview
|
||||
import com.hippo.ehviewer.client.exception.EhException
|
||||
import com.hippo.ehviewer.databinding.DialogGoToBinding
|
||||
import com.hippo.ehviewer.databinding.ItemGalleryPreviewBinding
|
||||
import com.hippo.ehviewer.databinding.SceneGalleryPreviewsBinding
|
||||
import com.hippo.util.getParcelableCompat
|
||||
import com.hippo.widget.ContentLayout.ContentHelper
|
||||
import com.hippo.widget.recyclerview.AutoGridLayoutManager
|
||||
import com.hippo.yorozuya.LayoutUtils
|
||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||
import java.util.Locale
|
||||
|
||||
class GalleryPreviewsScene : BaseToolbarScene() {
|
||||
@@ -49,7 +44,7 @@ class GalleryPreviewsScene : BaseToolbarScene() {
|
||||
private val binding
|
||||
get() = _binding!!
|
||||
private var mGalleryDetail: GalleryDetail? = null
|
||||
private var mAdapter: GalleryPreviewAdapter? = null
|
||||
private var mAdapter: GalleryPreviewsAdapter? = null
|
||||
private var mHelper: GalleryPreviewHelper? = null
|
||||
private var mHasFirstRefresh = false
|
||||
private var mNextPage: Boolean = false
|
||||
@@ -91,7 +86,9 @@ class GalleryPreviewsScene : BaseToolbarScene() {
|
||||
_binding = SceneGalleryPreviewsBinding.inflate(inflater, container, false)
|
||||
binding.contentLayout.hideFastScroll()
|
||||
setLiftOnScrollTargetView(binding.contentLayout.recyclerView)
|
||||
mAdapter = GalleryPreviewAdapter()
|
||||
mAdapter = GalleryPreviewsAdapter {
|
||||
mainActivity!!.startReaderActivity(mGalleryDetail!!, it.position)
|
||||
}
|
||||
binding.contentLayout.recyclerView.adapter = mAdapter
|
||||
val columnWidth = Settings.thumbSize
|
||||
val layoutManager =
|
||||
@@ -162,21 +159,6 @@ class GalleryPreviewsScene : BaseToolbarScene() {
|
||||
return false
|
||||
}
|
||||
|
||||
fun onItemClick(position: Int): Boolean {
|
||||
val context = context
|
||||
if (null != context && null != mHelper && null != mGalleryDetail) {
|
||||
val p = mHelper!!.getDataAtEx(position)
|
||||
if (p != null) {
|
||||
val intent = Intent(context, ReaderActivity::class.java)
|
||||
intent.action = ReaderActivity.ACTION_EH
|
||||
intent.putExtra(ReaderActivity.KEY_GALLERY_INFO, mGalleryDetail)
|
||||
intent.putExtra(ReaderActivity.KEY_PAGE, p.position)
|
||||
startActivity(intent)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun onGetPreviewListSuccess(result: Pair<List<GalleryPreview>, Int>, taskId: Int) {
|
||||
if (null != mHelper && mHelper!!.isCurrentTask(taskId) && null != mGalleryDetail) {
|
||||
mHelper!!.onGetPageData(taskId, result.second, 0, null, null, result.first)
|
||||
@@ -189,9 +171,6 @@ class GalleryPreviewsScene : BaseToolbarScene() {
|
||||
}
|
||||
}
|
||||
|
||||
private class GalleryPreviewHolder(val binding: ItemGalleryPreviewBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
private inner class GetPreviewListListener(
|
||||
context: Context,
|
||||
private val mTaskId: Int
|
||||
@@ -209,30 +188,6 @@ class GalleryPreviewsScene : BaseToolbarScene() {
|
||||
override fun onCancel() {}
|
||||
}
|
||||
|
||||
private inner class GalleryPreviewAdapter : RecyclerView.Adapter<GalleryPreviewHolder>() {
|
||||
private val mInflater: LayoutInflater = layoutInflater
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GalleryPreviewHolder {
|
||||
return GalleryPreviewHolder(ItemGalleryPreviewBinding.inflate(mInflater, parent, false))
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onBindViewHolder(holder: GalleryPreviewHolder, position: Int) {
|
||||
if (null != mHelper) {
|
||||
val preview = mHelper!!.getDataAtEx(position)
|
||||
if (preview != null) {
|
||||
preview.load(holder.binding.image)
|
||||
holder.binding.text.text = (preview.position + 1).toString()
|
||||
}
|
||||
}
|
||||
holder.itemView.setOnClickListener { onItemClick(position) }
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return if (mHelper != null) mHelper!!.size() else 0
|
||||
}
|
||||
}
|
||||
|
||||
private inner class GalleryPreviewHelper : ContentHelper<GalleryPreview>() {
|
||||
override fun getPageData(
|
||||
taskId: Int,
|
||||
@@ -258,18 +213,13 @@ class GalleryPreviewsScene : BaseToolbarScene() {
|
||||
override val context
|
||||
get() = this@GalleryPreviewsScene.requireContext()
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
override fun notifyDataSetChanged() {
|
||||
if (mAdapter != null) {
|
||||
mAdapter!!.notifyDataSetChanged()
|
||||
}
|
||||
override fun notifyDataSetChanged(callback: () -> Unit) {
|
||||
mAdapter?.submitList(data.toMutableList(), callback)
|
||||
}
|
||||
|
||||
override fun notifyItemRangeInserted(positionStart: Int, itemCount: Int) {
|
||||
if (mAdapter != null) {
|
||||
mAdapter!!.notifyItemRangeInserted(positionStart, itemCount)
|
||||
}
|
||||
}
|
||||
override fun notifyDataSetChanged() {}
|
||||
|
||||
override fun notifyItemRangeInserted(positionStart: Int, itemCount: Int) {}
|
||||
|
||||
override fun isDuplicate(d1: GalleryPreview, d2: GalleryPreview): Boolean {
|
||||
return false
|
||||
|
||||
@@ -267,6 +267,10 @@ class ContentLayout(context: Context, attrs: AttributeSet? = null) : FrameLayout
|
||||
)
|
||||
|
||||
protected abstract val context: Context
|
||||
protected open fun notifyDataSetChanged(callback: () -> Unit) {
|
||||
callback()
|
||||
}
|
||||
|
||||
protected abstract fun notifyDataSetChanged()
|
||||
protected abstract fun notifyItemRangeInserted(positionStart: Int, itemCount: Int)
|
||||
protected open fun onScrollToPosition(position: Int) {}
|
||||
@@ -282,6 +286,9 @@ class ContentLayout(context: Context, attrs: AttributeSet? = null) : FrameLayout
|
||||
mEmptyString = str
|
||||
}
|
||||
|
||||
val data: List<E>
|
||||
get() = mData
|
||||
|
||||
fun getDataAtEx(location: Int): E? {
|
||||
return if (location >= 0 && location < mData.size) {
|
||||
mData[location]
|
||||
@@ -339,9 +346,11 @@ class ContentLayout(context: Context, attrs: AttributeSet? = null) : FrameLayout
|
||||
onClearData()
|
||||
notifyDataSetChanged()
|
||||
|
||||
// Not found
|
||||
// Ui change, show empty string
|
||||
showEmptyString()
|
||||
notifyDataSetChanged {
|
||||
// Not found
|
||||
// Ui change, show empty string
|
||||
showEmptyString()
|
||||
}
|
||||
} else {
|
||||
mData.clear()
|
||||
onClearData()
|
||||
@@ -349,12 +358,14 @@ class ContentLayout(context: Context, attrs: AttributeSet? = null) : FrameLayout
|
||||
onAddData(data)
|
||||
notifyDataSetChanged()
|
||||
|
||||
// Ui change, show content
|
||||
showContent()
|
||||
notifyDataSetChanged {
|
||||
// Ui change, show content
|
||||
showContent()
|
||||
|
||||
// RecyclerView scroll
|
||||
if (binding.recyclerView.isAttachedToWindow) {
|
||||
scrollToPosition(0)
|
||||
// RecyclerView scroll
|
||||
if (binding.recyclerView.isAttachedToWindow) {
|
||||
scrollToPosition(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -391,20 +402,20 @@ class ContentLayout(context: Context, attrs: AttributeSet? = null) : FrameLayout
|
||||
onAddData(data)
|
||||
notifyItemRangeInserted(0, data.size)
|
||||
|
||||
// Ui change, show content
|
||||
binding.refreshLayout.isRefreshing = false
|
||||
binding.bottomProgress.hide()
|
||||
showContent()
|
||||
if (binding.recyclerView.isAttachedToWindow) {
|
||||
// RecyclerView scroll
|
||||
if (mCurrentTaskType == TYPE_PRE_PAGE_KEEP_POS) {
|
||||
binding.recyclerView.stopScroll()
|
||||
LayoutManagerUtils.scrollToPositionProperly(
|
||||
binding.recyclerView.layoutManager, context,
|
||||
dataSize - 1, mOnScrollToPositionListener
|
||||
)
|
||||
} else {
|
||||
scrollToPosition(0)
|
||||
notifyDataSetChanged {
|
||||
// Ui change, show content
|
||||
showContent()
|
||||
if (binding.recyclerView.isAttachedToWindow) {
|
||||
// RecyclerView scroll
|
||||
if (mCurrentTaskType == TYPE_PRE_PAGE_KEEP_POS) {
|
||||
binding.recyclerView.stopScroll()
|
||||
LayoutManagerUtils.scrollToPositionProperly(
|
||||
binding.recyclerView.layoutManager, context,
|
||||
dataSize - 1, mOnScrollToPositionListener
|
||||
)
|
||||
} else {
|
||||
scrollToPosition(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -437,16 +448,16 @@ class ContentLayout(context: Context, attrs: AttributeSet? = null) : FrameLayout
|
||||
onAddData(data)
|
||||
notifyItemRangeInserted(oldDataSize, dataSize)
|
||||
|
||||
// Ui change, show content
|
||||
binding.refreshLayout.isRefreshing = false
|
||||
binding.bottomProgress.hide()
|
||||
showContent()
|
||||
if (binding.recyclerView.isAttachedToWindow) {
|
||||
if (mCurrentTaskType == TYPE_NEXT_PAGE_KEEP_POS) {
|
||||
binding.recyclerView.stopScroll()
|
||||
binding.recyclerView.smoothScrollBy(0, mNextPageScrollSize)
|
||||
} else {
|
||||
scrollToPosition(oldDataSize)
|
||||
notifyDataSetChanged {
|
||||
// Ui change, show content
|
||||
showContent()
|
||||
if (binding.recyclerView.isAttachedToWindow) {
|
||||
if (mCurrentTaskType == TYPE_NEXT_PAGE_KEEP_POS) {
|
||||
binding.recyclerView.stopScroll()
|
||||
binding.recyclerView.smoothScrollBy(0, mNextPageScrollSize)
|
||||
} else {
|
||||
scrollToPosition(oldDataSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -466,9 +477,11 @@ class ContentLayout(context: Context, attrs: AttributeSet? = null) : FrameLayout
|
||||
onClearData()
|
||||
notifyDataSetChanged()
|
||||
|
||||
// Not found
|
||||
// Ui change, show empty string
|
||||
showEmptyString()
|
||||
notifyDataSetChanged {
|
||||
// Not found
|
||||
// Ui change, show empty string
|
||||
showEmptyString()
|
||||
}
|
||||
} else {
|
||||
mData.clear()
|
||||
onClearData()
|
||||
@@ -476,11 +489,13 @@ class ContentLayout(context: Context, attrs: AttributeSet? = null) : FrameLayout
|
||||
onAddData(data)
|
||||
notifyDataSetChanged()
|
||||
|
||||
// Ui change, show content
|
||||
showContent()
|
||||
if (binding.recyclerView.isAttachedToWindow) {
|
||||
// RecyclerView scroll
|
||||
scrollToPosition(0)
|
||||
notifyDataSetChanged {
|
||||
// Ui change, show content
|
||||
showContent()
|
||||
if (binding.recyclerView.isAttachedToWindow) {
|
||||
// RecyclerView scroll
|
||||
scrollToPosition(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -513,22 +528,24 @@ class ContentLayout(context: Context, attrs: AttributeSet? = null) : FrameLayout
|
||||
mData.addAll(oldIndexStart, data)
|
||||
onAddData(data)
|
||||
notifyDataSetChanged()
|
||||
var i = mCurrentTaskPage - mStartPage
|
||||
val n = mPageDivider.size
|
||||
while (i < n) {
|
||||
mPageDivider[i] = mPageDivider[i] - oldIndexEnd + newIndexEnd
|
||||
i++
|
||||
}
|
||||
if (mData.isEmpty()) {
|
||||
// Ui change, show empty string
|
||||
showEmptyString()
|
||||
} else {
|
||||
// Ui change, show content
|
||||
showContent()
|
||||
notifyDataSetChanged {
|
||||
var i = mCurrentTaskPage - mStartPage
|
||||
val n = mPageDivider.size
|
||||
while (i < n) {
|
||||
mPageDivider[i] = mPageDivider[i] - oldIndexEnd + newIndexEnd
|
||||
i++
|
||||
}
|
||||
if (mData.isEmpty()) {
|
||||
// Ui change, show empty string
|
||||
showEmptyString()
|
||||
} else {
|
||||
// Ui change, show content
|
||||
showContent()
|
||||
|
||||
// RecyclerView scroll
|
||||
if (newIndexEnd > oldIndexEnd && newIndexEnd > 0 && binding.recyclerView.isAttachedToWindow) {
|
||||
scrollToPosition(newIndexEnd - 1)
|
||||
// RecyclerView scroll
|
||||
if (newIndexEnd > oldIndexEnd && newIndexEnd > 0 && binding.recyclerView.isAttachedToWindow) {
|
||||
scrollToPosition(newIndexEnd - 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user