This commit is contained in:
tom5079
2021-01-09 19:18:26 +09:00
parent c8aa26e2d9
commit 619730e2ab
32 changed files with 825 additions and 1385 deletions

View File

@@ -19,33 +19,66 @@
package xyz.quaver.pupil.adapters
import android.content.Context
import android.graphics.drawable.Animatable
import android.net.Uri
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.widget.ImageView
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.drawee.controller.BaseControllerListener
import com.facebook.drawee.drawable.ScalingUtils
import com.facebook.drawee.interfaces.DraweeController
import com.facebook.drawee.view.SimpleDraweeView
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import com.facebook.imagepipeline.image.ImageInfo
import com.github.piasy.biv.loader.ImageLoader
import com.github.piasy.biv.view.BigImageView
import com.github.piasy.biv.view.ImageShownCallback
import com.github.piasy.biv.view.ImageViewFactory
import xyz.quaver.pupil.R
import xyz.quaver.pupil.databinding.ReaderItemBinding
import xyz.quaver.pupil.util.downloader.Cache
import xyz.quaver.pupil.util.downloader.Downloader
import java.io.File
import java.lang.Exception
import kotlin.math.roundToInt
class ReaderAdapter(
private val context: Context,
private val source: String,
private val itemID: String
) : RecyclerView.Adapter<ReaderAdapter.ViewHolder>() {
data class ReaderItem(
val progress: Float,
val image: File?
)
class ReaderAdapter : ListAdapter<ReaderItem, ReaderAdapter.ViewHolder>(ReaderItemDiffCallback()) {
var onItemClickListener : (() -> (Unit))? = null
var fullscreen = false
inner class ViewHolder(private val binding: ReaderItemBinding) : RecyclerView.ViewHolder(binding.root) {
init {
with (binding.image) {
setImageViewFactory(FrescoImageViewFactory().apply {
updateView = { imageInfo ->
layoutParams.height = imageInfo.height
(mainView as? SimpleDraweeView)?.aspectRatio = imageInfo.width / imageInfo.height.toFloat()
}
})
setImageShownCallback(object: ImageShownCallback {
override fun onMainImageShown() {
binding.progressGroup.visibility = View.INVISIBLE
binding.root.layoutParams.height = if (fullscreen)
MATCH_PARENT
else
WRAP_CONTENT
}
override fun onThumbnailShown() {}
})
setFailureImage(ContextCompat.getDrawable(itemView.context, R.drawable.image_broken_variant))
setOnClickListener {
onItemClickListener?.invoke()
@@ -60,42 +93,35 @@ class ReaderAdapter(
}
fun bind(position: Int) {
recycle()
binding.root.layoutParams.height = MATCH_PARENT
binding.readerIndex.text = (position+1).toString()
val image = Cache.getInstance(context, source, itemID).getImage(position)?.uri
val (progress, image) = getItem(position)
if (image != null)
binding.image.showImage(image)
else {
val progress = Downloader.getInstance(context).getProgress(source, itemID)?.get(position) ?: 0F
binding.progressGroup.visibility = View.VISIBLE
if (image != null) {
binding.root.background = null
binding.image.showImage(Uri.fromFile(image))
} else {
binding.root.setBackgroundResource(R.drawable.reader_item_boundary)
if (progress == Float.NEGATIVE_INFINITY)
with (binding.image) {
showImage(Uri.EMPTY)
setOnClickListener {
if (Downloader.getInstance(context).getProgress(source, itemID)?.get(position) == Float.NEGATIVE_INFINITY)
Downloader.getInstance(context).retry(source, itemID)
}
}
else {
binding.image.showImage(Uri.EMPTY)
else
binding.readerItemProgressbar.progress = progress.roundToInt()
CoroutineScope(Dispatchers.Main).launch {
delay(1000)
notifyItemChanged(position)
}
}
}
}
fun clear() {
binding.image.mainView.let {
when (it) {
is SubsamplingScaleImageView ->
it.recycle()
is SimpleDraweeView ->
it.controller = null
fun recycle() {
binding.image.mainView.run {
when (this) {
is SubsamplingScaleImageView -> recycle()
is SimpleDraweeView -> recycle()
is ImageView -> setImageBitmap(null)
}
}
}
@@ -109,10 +135,102 @@ class ReaderAdapter(
holder.bind(position)
}
override fun getItemCount() = Downloader.getInstance(context).getProgress(source, itemID)?.size ?: 0
override fun onViewRecycled(holder: ViewHolder) {
holder.clear()
super.onViewRecycled(holder)
holder.recycle()
}
}
class ReaderItemDiffCallback : DiffUtil.ItemCallback<ReaderItem>() {
override fun areItemsTheSame(oldItem: ReaderItem, newItem: ReaderItem) =
true
override fun areContentsTheSame(oldItem: ReaderItem, newItem: ReaderItem) =
oldItem == newItem
}
class FrescoImageViewFactory : ImageViewFactory() {
var updateView: ((ImageInfo) -> Unit)? = null
override fun createAnimatedImageView(
context: Context, imageType: Int,
initScaleType: Int
): View {
val view = SimpleDraweeView(context)
view.hierarchy.actualImageScaleType = scaleType(initScaleType)
return view
}
override fun loadAnimatedContent(
view: View, imageType: Int,
imageFile: File
) {
if (view is SimpleDraweeView) {
val controller: DraweeController = Fresco.newDraweeControllerBuilder()
.setOldController(view.controller)
.setUri(Uri.parse("file://" + imageFile.absolutePath))
.setAutoPlayAnimations(true)
.setControllerListener(object: BaseControllerListener<ImageInfo>() {
override fun onIntermediateImageSet(id: String?, imageInfo: ImageInfo?) {
imageInfo?.let { updateView?.invoke(it) }
}
override fun onFinalImageSet(id: String?, imageInfo: ImageInfo?, animatable: Animatable?) {
imageInfo?.let { updateView?.invoke(it) }
}
})
.build()
view.controller = controller
}
}
override fun createThumbnailView(
context: Context,
scaleType: ImageView.ScaleType, willLoadFromNetwork: Boolean
): View {
return if (willLoadFromNetwork) {
val thumbnailView = SimpleDraweeView(context)
thumbnailView.hierarchy.actualImageScaleType = scaleType(scaleType)
thumbnailView
} else {
super.createThumbnailView(context, scaleType, false)
}
}
override fun loadThumbnailContent(view: View, thumbnail: Uri) {
if (view is SimpleDraweeView) {
val controller: DraweeController = Fresco.newDraweeControllerBuilder()
.setOldController(view.controller)
.setUri(thumbnail)
.build()
view.controller = controller
}
}
private fun scaleType(value: Int): ScalingUtils.ScaleType {
return when (value) {
BigImageView.INIT_SCALE_TYPE_CENTER -> ScalingUtils.ScaleType.CENTER
BigImageView.INIT_SCALE_TYPE_CENTER_CROP -> ScalingUtils.ScaleType.CENTER_CROP
BigImageView.INIT_SCALE_TYPE_CENTER_INSIDE -> ScalingUtils.ScaleType.CENTER_INSIDE
BigImageView.INIT_SCALE_TYPE_FIT_END -> ScalingUtils.ScaleType.FIT_END
BigImageView.INIT_SCALE_TYPE_FIT_START -> ScalingUtils.ScaleType.FIT_START
BigImageView.INIT_SCALE_TYPE_FIT_XY -> ScalingUtils.ScaleType.FIT_XY
BigImageView.INIT_SCALE_TYPE_FIT_CENTER -> ScalingUtils.ScaleType.FIT_CENTER
else -> ScalingUtils.ScaleType.FIT_CENTER
}
}
private fun scaleType(scaleType: ImageView.ScaleType): ScalingUtils.ScaleType {
return when (scaleType) {
ImageView.ScaleType.CENTER -> ScalingUtils.ScaleType.CENTER
ImageView.ScaleType.CENTER_CROP -> ScalingUtils.ScaleType.CENTER_CROP
ImageView.ScaleType.CENTER_INSIDE -> ScalingUtils.ScaleType.CENTER_INSIDE
ImageView.ScaleType.FIT_END -> ScalingUtils.ScaleType.FIT_END
ImageView.ScaleType.FIT_START -> ScalingUtils.ScaleType.FIT_START
ImageView.ScaleType.FIT_XY -> ScalingUtils.ScaleType.FIT_XY
ImageView.ScaleType.FIT_CENTER -> ScalingUtils.ScaleType.FIT_CENTER
else -> ScalingUtils.ScaleType.FIT_CENTER
}
}
}