1 package expo.modules.image 2 3 import android.util.Log 4 import com.bumptech.glide.Glide 5 import com.bumptech.glide.load.model.GlideUrl 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.cancel 13 import kotlinx.coroutines.launch 14 import java.lang.Exception 15 import java.lang.IllegalStateException 16 import java.util.concurrent.CancellationException 17 18 class ExpoImageModule(val context: ReactApplicationContext) : ReactContextBaseJavaModule(context) { 19 private val moduleCoroutineScope = CoroutineScope(Dispatchers.IO) 20 override fun getName() = "ExpoImageModule" 21 22 @ReactMethod 23 fun prefetch(url: String, promise: Promise) { 24 moduleCoroutineScope.launch { 25 try { 26 val glideUrl = GlideUrl(url) 27 val result = Glide.with(context) 28 .download(glideUrl) 29 .submit() 30 .awaitGet() 31 if (result != null) { 32 promise.resolve(null) 33 } else { 34 promise.reject("ERR_IMAGE_PREFETCH_FAILURE", "Failed to prefetch the image: ${url}.") 35 } 36 } catch (e: Exception) { 37 promise.reject("ERR_IMAGE_PREFETCH_FAILURE", "Failed to prefetch the image: ${e.message}", e) 38 } 39 } 40 } 41 42 override fun onCatalystInstanceDestroy() { 43 try { 44 // TODO: Use [expo.modules.core.errors.ModuleDestroyedException] when migrated to Expo Module 45 moduleCoroutineScope.cancel(CancellationException("ExpoImage module is destroyed. Cancelling all jobs.")) 46 } catch (e: IllegalStateException) { 47 Log.w("ExpoImageModule", "No coroutines to cancel") 48 } 49 50 super.onCatalystInstanceDestroy() 51 } 52 } 53