chinwag-android/app/src/main/java/com/keylesspalace/tusky/util/GlideExtensions.kt
Christophe Beyls f9221b3d75
Improve RequestBuilder.submitAsync() to ensure the coroutine continuation is resumed only once (#4436)
`RequestListener.onResourceReady()` may also be called to provide the
placeholder image when the request is starting or when it is cleared.

Check if the current request is complete (its status set to COMPLETE) to
determine if the Glide resource is for a thumbnail/placeholder or the
final image, and resume the coroutine only for the final image (or in
case of error).
This logic is [borrowed from the Glide Flow
API](a7351b0ecf/integration/ktx/src/main/java/com/bumptech/glide/integration/ktx/Flows.kt (L378)).
2024-05-12 11:25:49 +02:00

48 lines
1.7 KiB
Kotlin

package com.keylesspalace.tusky.util
import com.bumptech.glide.RequestBuilder
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlinx.coroutines.suspendCancellableCoroutine
/**
* Allows waiting for a Glide request to complete without blocking a background thread.
*/
suspend fun <R> RequestBuilder<R>.submitAsync(
width: Int = Target.SIZE_ORIGINAL,
height: Int = Target.SIZE_ORIGINAL
): R {
return suspendCancellableCoroutine { continuation ->
val target = addListener(
object : RequestListener<R> {
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<R>,
isFirstResource: Boolean
): Boolean {
continuation.resumeWithException(e ?: GlideException("Image loading failed"))
return false
}
override fun onResourceReady(
resource: R & Any,
model: Any,
target: Target<R>?,
dataSource: DataSource,
isFirstResource: Boolean
): Boolean {
if (target?.request?.isComplete == true) {
continuation.resume(resource)
}
return false
}
}
).submit(width, height)
continuation.invokeOnCancellation { target.cancel(true) }
}
}