Introduce BaseListAdapter and BaseViewHolder

This commit is contained in:
FooIbar authored and tarsin committed 2023-03-10 11:00:24 +08:00
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)
}
}
}
}