1 package expo.modules.image
2 
3 import com.bumptech.glide.Glide
4 import com.bumptech.glide.load.model.GlideUrl
5 import com.bumptech.glide.request.FutureTarget
6 import com.facebook.react.bridge.Promise
7 import com.facebook.react.bridge.ReactApplicationContext
8 import com.facebook.react.bridge.ReactContextBaseJavaModule
9 import com.facebook.react.bridge.ReactMethod
10 import kotlinx.coroutines.CoroutineScope
11 import kotlinx.coroutines.Dispatchers
12 import kotlinx.coroutines.launch
13 import kotlinx.coroutines.runInterruptible
14 import java.lang.Exception
15 
16 /**
17  * We need to convert blocking java.util.concurrent.Future result
18  * into non-blocking suspend function. We use extension function for that
19  */
20 suspend fun <T> FutureTarget<T>.awaitGet() = runInterruptible(Dispatchers.IO) { get() }
21 
22 class ExpoImageModule(val context: ReactApplicationContext) : ReactContextBaseJavaModule(context) {
23   private val moduleCoroutineScope = CoroutineScope(Dispatchers.IO)
24   override fun getName() = "ExpoImageModule"
25 
26   @ReactMethod
27   fun prefetch(url: String, promise: Promise) {
28     moduleCoroutineScope.launch {
29       try {
30         val glideUrl = GlideUrl(url)
31         val result = Glide.with(context)
32             .download(glideUrl)
33             .submit()
34             .awaitGet()
35         if (result != null) {
36           promise.resolve(null)
37         } else {
38           promise.reject("ERR_IMAGE_PREFETCH_FAILURE", "Failed to prefetch the image: ${url}.")
39         }
40       } catch (e: Exception) {
41         promise.reject("ERR_IMAGE_PREFETCH_FAILURE", "Failed to prefetch the image: ${e.message}", e)
42       }
43     }
44   }
45 }
46