Rely solely on recyclerview for lazy loading

Closes https://github.com/FossifyOrg/Gallery/issues/136

- Remove manual lazy loading mechanism
- Disable cross fade when loading from cache
This commit is contained in:
Naveen Singh 2024-09-24 21:53:01 +05:30
parent 85f5f43b29
commit ff836d8c24
No known key found for this signature in database
GPG key ID: AF5D43C216778C0B
3 changed files with 37 additions and 69 deletions

View file

@ -4,8 +4,6 @@ import android.content.Intent
import android.content.pm.ShortcutInfo
import android.content.pm.ShortcutManager
import android.graphics.drawable.Icon
import android.os.Handler
import android.os.Looper
import android.view.Menu
import android.view.View
import android.view.ViewGroup
@ -38,11 +36,8 @@ import org.fossify.gallery.models.ThumbnailSection
class MediaAdapter(
activity: BaseSimpleActivity, var media: ArrayList<ThumbnailItem>, val listener: MediaOperationsListener?, val isAGetIntent: Boolean,
val allowMultiplePicks: Boolean, val path: String, recyclerView: MyRecyclerView, itemClick: (Any) -> Unit
) :
MyRecyclerViewAdapter(activity, recyclerView, itemClick), RecyclerViewFastScroller.OnPopupTextUpdate {
) : MyRecyclerViewAdapter(activity, recyclerView, itemClick), RecyclerViewFastScroller.OnPopupTextUpdate {
private val INSTANT_LOAD_DURATION = 2000L
private val IMAGE_LOAD_DELAY = 100L
private val ITEM_SECTION = 0
private val ITEM_MEDIUM_VIDEO_PORTRAIT = 1
private val ITEM_MEDIUM_PHOTO = 2
@ -50,10 +45,7 @@ class MediaAdapter(
private val config = activity.config
private val viewType = config.getFolderViewType(if (config.showAll) SHOW_ALL else path)
private val isListViewType = viewType == VIEW_TYPE_LIST
private var visibleItemPaths = ArrayList<String>()
private var rotatedImagePaths = ArrayList<String>()
private var loadImageInstantly = false
private var delayHandler = Handler(Looper.getMainLooper())
private var currentMediaHash = media.hashCode()
private val hasOTGConnected = activity.hasOTGConnected()
@ -69,7 +61,6 @@ class MediaAdapter(
init {
setupDragListener(true)
enableInstantLoad()
}
override fun getActionMenuId() = R.menu.cab_media
@ -97,10 +88,6 @@ class MediaAdapter(
override fun onBindViewHolder(holder: MyRecyclerViewAdapter.ViewHolder, position: Int) {
val tmbItem = media.getOrNull(position) ?: return
if (tmbItem is Medium) {
visibleItemPaths.add(tmbItem.path)
}
val allowLongPress = (!isAGetIntent || allowMultiplePicks) && tmbItem is Medium
holder.bindView(tmbItem, tmbItem is Medium, allowLongPress) { itemView, adapterPosition ->
if (tmbItem is Medium) {
@ -197,7 +184,6 @@ class MediaAdapter(
super.onViewRecycled(holder)
if (!activity.isDestroyed) {
val itemView = holder.itemView
visibleItemPaths.remove(itemView.allViews.firstOrNull { it.id == R.id.medium_name }?.tag)
val tmb = itemView.allViews.firstOrNull { it.id == R.id.medium_thumbnail }
if (tmb != null) {
Glide.with(activity).clear(tmb)
@ -254,7 +240,6 @@ class MediaAdapter(
activity.updateDBMediaPath(firstPath, it)
activity.runOnUiThread {
enableInstantLoad()
listener?.refreshItems()
finishActMode()
}
@ -262,7 +247,6 @@ class MediaAdapter(
}
} else {
RenameDialog(activity, getSelectedPaths(), true) {
enableInstantLoad()
listener?.refreshItems()
finishActMode()
}
@ -572,7 +556,6 @@ class MediaAdapter(
if (thumbnailItems.hashCode() != currentMediaHash) {
currentMediaHash = thumbnailItems.hashCode()
media = thumbnailItems
enableInstantLoad()
notifyDataSetChanged()
finishActMode()
}
@ -580,7 +563,6 @@ class MediaAdapter(
fun updateDisplayFilenames(displayFilenames: Boolean) {
this.displayFilenames = displayFilenames
enableInstantLoad()
notifyDataSetChanged()
}
@ -599,13 +581,6 @@ class MediaAdapter(
notifyDataSetChanged()
}
private fun enableInstantLoad() {
loadImageInstantly = true
delayHandler.postDelayed({
loadImageInstantly = false
}, INSTANT_LOAD_DURATION)
}
private fun setupThumbnail(view: View, medium: Medium) {
val isSelected = selectedKeys.contains(medium.path.hashCode())
bindItem(view, medium).apply {
@ -681,46 +656,21 @@ class MediaAdapter(
else -> ROUNDED_CORNERS_NONE
}
if (loadImageInstantly) {
activity.loadImage(
type = medium.type,
path = path,
target = mediumThumbnail,
horizontalScroll = scrollHorizontally,
animateGifs = animateGifs,
cropThumbnails = cropThumbnails,
roundCorners = roundedCorners,
signature = medium.getKey(),
skipMemoryCacheAtPaths = rotatedImagePaths,
onError = {
mediumThumbnail.scaleType = ImageView.ScaleType.CENTER
mediumThumbnail.setImageDrawable(AppCompatResources.getDrawable(activity, R.drawable.ic_vector_warning_colored))
}
)
} else {
mediumThumbnail.setImageDrawable(null)
mediumThumbnail.isHorizontalScrolling = scrollHorizontally
delayHandler.postDelayed({
val isVisible = visibleItemPaths.contains(medium.path)
if (isVisible) {
activity.loadImage(
type = medium.type,
path = path,
target = mediumThumbnail,
horizontalScroll = scrollHorizontally,
animateGifs = animateGifs,
cropThumbnails = cropThumbnails,
roundCorners = roundedCorners,
signature = medium.getKey(),
skipMemoryCacheAtPaths = rotatedImagePaths,
onError = {
mediumThumbnail.scaleType = ImageView.ScaleType.CENTER
mediumThumbnail.setImageDrawable(AppCompatResources.getDrawable(activity, R.drawable.ic_vector_warning_colored))
}
)
}
}, IMAGE_LOAD_DELAY)
}
activity.loadImage(
type = medium.type,
path = path,
target = mediumThumbnail,
horizontalScroll = scrollHorizontally,
animateGifs = animateGifs,
cropThumbnails = cropThumbnails,
roundCorners = roundedCorners,
signature = medium.getKey(),
skipMemoryCacheAtPaths = rotatedImagePaths,
onError = {
mediumThumbnail.scaleType = ImageView.ScaleType.CENTER
mediumThumbnail.setImageDrawable(AppCompatResources.getDrawable(activity, R.drawable.ic_vector_warning_colored))
}
)
if (isListViewType) {
mediumName.setTextColor(textColor)

View file

@ -28,7 +28,6 @@ import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.load.resource.bitmap.CenterCrop
import com.bumptech.glide.load.resource.bitmap.FitCenter
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.Target
@ -586,7 +585,7 @@ fun Context.loadImageBase(
.load(path)
.apply(options)
.set(WebpDownsampler.USE_SYSTEM_DECODER, false) // CVE-2023-4863
.transition(DrawableTransitionOptions.withCrossFade(crossFadeDuration))
.transition(getOptionalCrossFadeTransition(crossFadeDuration))
builder = builder.listener(object : RequestListener<Drawable> {
override fun onLoadFailed(e: GlideException?, model: Any?, targetBitmap: Target<Drawable>, isFirstResource: Boolean): Boolean {
@ -627,7 +626,7 @@ fun Context.loadSVG(
.listener(SvgSoftwareLayerSetter())
.load(path)
.apply(options)
.transition(DrawableTransitionOptions.withCrossFade(crossFadeDuration))
.transition(getOptionalCrossFadeTransition(crossFadeDuration))
if (roundCorners != ROUNDED_CORNERS_NONE) {
val cornerSize =

View file

@ -0,0 +1,19 @@
package org.fossify.gallery.extensions
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
import com.bumptech.glide.request.transition.DrawableCrossFadeFactory
import com.bumptech.glide.request.transition.TransitionFactory
/**
* Cross fade transition option that disabled fading when loading from cache.
*/
fun getOptionalCrossFadeTransition(duration: Int): DrawableTransitionOptions {
return DrawableTransitionOptions.with(
TransitionFactory { dataSource, isFirstResource ->
if (dataSource == DataSource.RESOURCE_DISK_CACHE) return@TransitionFactory null
DrawableCrossFadeFactory.Builder(duration).build().build(dataSource, isFirstResource)
}
)
}