From a6a2a6ebbae6eeda82642aef8efd345e5bf93df0 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Fri, 10 Mar 2023 01:14:00 +0800 Subject: [PATCH] Introduce BaseListAdapter and BaseViewHolder --- .../ehviewer/client/data/GalleryPreview.kt | 2 +- .../com/hippo/ehviewer/ui/MainActivity.kt | 10 ++ .../ehviewer/ui/scene/BaseListAdapter.kt | 12 ++ .../hippo/ehviewer/ui/scene/BaseViewHolder.kt | 17 +++ .../ui/scene/GalleryPreviewsAdapter.kt | 46 +++++++ .../ehviewer/ui/scene/GalleryPreviewsScene.kt | 68 ++-------- .../java/com/hippo/widget/ContentLayout.kt | 127 ++++++++++-------- 7 files changed, 167 insertions(+), 115 deletions(-) create mode 100644 app/src/main/java/com/hippo/ehviewer/ui/scene/BaseListAdapter.kt create mode 100644 app/src/main/java/com/hippo/ehviewer/ui/scene/BaseViewHolder.kt create mode 100644 app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryPreviewsAdapter.kt diff --git a/app/src/main/java/com/hippo/ehviewer/client/data/GalleryPreview.kt b/app/src/main/java/com/hippo/ehviewer/client/data/GalleryPreview.kt index fe39dbfc9..f6c59e7c0 100644 --- a/app/src/main/java/com/hippo/ehviewer/client/data/GalleryPreview.kt +++ b/app/src/main/java/com/hippo/ehviewer/client/data/GalleryPreview.kt @@ -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, diff --git a/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.kt b/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.kt index acf1d208d..9d17f7b27 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.kt @@ -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 { diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/BaseListAdapter.kt b/app/src/main/java/com/hippo/ehviewer/ui/scene/BaseListAdapter.kt new file mode 100644 index 000000000..4aba1b673 --- /dev/null +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/BaseListAdapter.kt @@ -0,0 +1,12 @@ +package com.hippo.ehviewer.ui.scene + +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter + +abstract class BaseListAdapter(diffCallback: DiffUtil.ItemCallback) : + ListAdapter>(diffCallback) { + override fun onBindViewHolder(holder: BaseViewHolder, position: Int) { + val item = getItem(position) + holder.bind(item) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/BaseViewHolder.kt b/app/src/main/java/com/hippo/ehviewer/ui/scene/BaseViewHolder.kt new file mode 100644 index 000000000..4ffdc54ec --- /dev/null +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/BaseViewHolder.kt @@ -0,0 +1,17 @@ +package com.hippo.ehviewer.ui.scene + +import androidx.recyclerview.widget.RecyclerView +import androidx.viewbinding.ViewBinding + +abstract class BaseViewHolder(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) +} \ No newline at end of file diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryPreviewsAdapter.kt b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryPreviewsAdapter.kt new file mode 100644 index 000000000..2fddbe7ee --- /dev/null +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryPreviewsAdapter.kt @@ -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(PreviewDiffCallback) { + class GalleryPreviewHolder( + private val binding: ItemGalleryPreviewBinding, + onClick: (GalleryPreview) -> Unit + ) : BaseViewHolder(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 { + 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() { + override fun areItemsTheSame(oldItem: GalleryPreview, newItem: GalleryPreview): Boolean { + return oldItem.position == newItem.position + } + + override fun areContentsTheSame(oldItem: GalleryPreview, newItem: GalleryPreview): Boolean { + return oldItem == newItem + } +} \ No newline at end of file diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryPreviewsScene.kt b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryPreviewsScene.kt index 0de356960..01eb913b9 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryPreviewsScene.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryPreviewsScene.kt @@ -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, 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() { - 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() { 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 diff --git a/app/src/main/java/com/hippo/widget/ContentLayout.kt b/app/src/main/java/com/hippo/widget/ContentLayout.kt index 1c846dfba..e9a1a495a 100644 --- a/app/src/main/java/com/hippo/widget/ContentLayout.kt +++ b/app/src/main/java/com/hippo/widget/ContentLayout.kt @@ -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 + 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) + } } } }