diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 514f471bf8e4..07214d27c471 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -10,6 +10,8 @@ { -+ -+ @Override -+ public boolean handles(@NonNull InputStream source, @NonNull Options options) throws IOException { -+ return true; -+ } -+ -+ @Nullable -+ @Override -+ public Resource decode(@NonNull InputStream source, int width, int height, @NonNull Options options) throws IOException { -+ BitmapFactory.Options bitmapOptions = new BitmapFactory.Options(); -+ bitmapOptions.inJustDecodeBounds = true; -+ BitmapFactory.decodeStream(source, null, bitmapOptions); -+ -+ // BitmapFactory#decodeStream leaves stream's position where ever it was after reading the encoded data -+ // https://developer.android.com/reference/android/graphics/BitmapFactory#decodeStream(java.io.InputStream) -+ // so we need to rewind the stream to be able to read image header with exif values -+ source.reset(); -+ -+ int orientation = new ExifInterface(source).getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED); -+ if (orientation == ExifInterface.ORIENTATION_ROTATE_90 || orientation == ExifInterface.ORIENTATION_ROTATE_270) { -+ int tmpWidth = bitmapOptions.outWidth; -+ bitmapOptions.outWidth = bitmapOptions.outHeight; -+ bitmapOptions.outHeight = tmpWidth; -+ } -+ return new SimpleResource(bitmapOptions); -+ } -+} -\ No newline at end of file -diff --git a/node_modules/react-native-fast-image/android/src/main/java/com/dylanvann/fastimage/BitmapSizeTranscoder.java b/node_modules/react-native-fast-image/android/src/main/java/com/dylanvann/fastimage/BitmapSizeTranscoder.java -new file mode 100644 -index 0000000..7d208d1 ---- /dev/null -+++ b/node_modules/react-native-fast-image/android/src/main/java/com/dylanvann/fastimage/BitmapSizeTranscoder.java -@@ -0,0 +1,23 @@ -+package com.dylanvann.fastimage; -+ -+import android.graphics.BitmapFactory; -+ -+import androidx.annotation.NonNull; -+import androidx.annotation.Nullable; -+ -+import com.bumptech.glide.load.Options; -+import com.bumptech.glide.load.engine.Resource; -+import com.bumptech.glide.load.resource.SimpleResource; -+import com.bumptech.glide.load.resource.transcode.ResourceTranscoder; -+ -+public class BitmapSizeTranscoder implements ResourceTranscoder { -+ @Nullable -+ @Override -+ public Resource transcode(@NonNull Resource toTranscode, @NonNull Options options) { -+ BitmapFactory.Options bitmap = toTranscode.get(); -+ Size size = new Size(); -+ size.width = bitmap.outWidth; -+ size.height = bitmap.outHeight; -+ return new SimpleResource(size); -+ } -+} -\ No newline at end of file -diff --git a/node_modules/react-native-fast-image/android/src/main/java/com/dylanvann/fastimage/FastImageOkHttpProgressGlideModule.java b/node_modules/react-native-fast-image/android/src/main/java/com/dylanvann/fastimage/FastImageOkHttpProgressGlideModule.java -index 811292a..f60b87c 100644 ---- a/node_modules/react-native-fast-image/android/src/main/java/com/dylanvann/fastimage/FastImageOkHttpProgressGlideModule.java -+++ b/node_modules/react-native-fast-image/android/src/main/java/com/dylanvann/fastimage/FastImageOkHttpProgressGlideModule.java -@@ -2,6 +2,7 @@ package com.dylanvann.fastimage; - - import android.content.Context; - import androidx.annotation.NonNull; -+import android.graphics.BitmapFactory; - - import com.bumptech.glide.Glide; - import com.bumptech.glide.Registry; -@@ -47,6 +48,9 @@ public class FastImageOkHttpProgressGlideModule extends LibraryGlideModule { - .build(); - OkHttpUrlLoader.Factory factory = new OkHttpUrlLoader.Factory(client); - registry.replace(GlideUrl.class, InputStream.class, factory); -+ // Decoder + Transcoder pair for InputStream -> Size -+ registry.prepend(InputStream.class, BitmapFactory.Options.class, new BitmapSizeDecoder()); -+ registry.register(BitmapFactory.Options.class, Size.class, new BitmapSizeTranscoder()); - } - - private static Interceptor createInterceptor(final ResponseProgressListener listener) { -diff --git a/node_modules/react-native-fast-image/android/src/main/java/com/dylanvann/fastimage/FastImageRequestListener.java b/node_modules/react-native-fast-image/android/src/main/java/com/dylanvann/fastimage/FastImageRequestListener.java -index dbeb813..bf8f21c 100644 ---- a/node_modules/react-native-fast-image/android/src/main/java/com/dylanvann/fastimage/FastImageRequestListener.java -+++ b/node_modules/react-native-fast-image/android/src/main/java/com/dylanvann/fastimage/FastImageRequestListener.java -@@ -22,13 +22,6 @@ public class FastImageRequestListener implements RequestListener { - this.key = key; - } - -- private static WritableMap mapFromResource(Drawable resource) { -- WritableMap resourceData = new WritableNativeMap(); -- resourceData.putInt("width", resource.getIntrinsicWidth()); -- resourceData.putInt("height", resource.getIntrinsicHeight()); -- return resourceData; -- } -- - @Override - public boolean onLoadFailed(@androidx.annotation.Nullable GlideException e, Object model, Target target, boolean isFirstResource) { - FastImageOkHttpProgressGlideModule.forget(key); -@@ -53,7 +46,6 @@ public class FastImageRequestListener implements RequestListener { - ThemedReactContext context = (ThemedReactContext) view.getContext(); - RCTEventEmitter eventEmitter = context.getJSModule(RCTEventEmitter.class); - int viewId = view.getId(); -- eventEmitter.receiveEvent(viewId, REACT_ON_LOAD_EVENT, mapFromResource(resource)); - eventEmitter.receiveEvent(viewId, REACT_ON_LOAD_END_EVENT, new WritableNativeMap()); - return false; - } -diff --git a/node_modules/react-native-fast-image/android/src/main/java/com/dylanvann/fastimage/FastImageViewWithUrl.java b/node_modules/react-native-fast-image/android/src/main/java/com/dylanvann/fastimage/FastImageViewWithUrl.java -index 34fcf89..1339f5c 100644 ---- a/node_modules/react-native-fast-image/android/src/main/java/com/dylanvann/fastimage/FastImageViewWithUrl.java -+++ b/node_modules/react-native-fast-image/android/src/main/java/com/dylanvann/fastimage/FastImageViewWithUrl.java -@@ -2,6 +2,7 @@ package com.dylanvann.fastimage; - - import static com.dylanvann.fastimage.FastImageRequestListener.REACT_ON_ERROR_EVENT; - -+import androidx.annotation.NonNull; - import android.annotation.SuppressLint; - import android.content.Context; - import android.graphics.drawable.Drawable; -@@ -9,16 +10,24 @@ import android.graphics.drawable.Drawable; - import androidx.annotation.Nullable; - import androidx.appcompat.widget.AppCompatImageView; - -+import com.bumptech.glide.Glide; - import com.bumptech.glide.RequestBuilder; - import com.bumptech.glide.RequestManager; -+import com.bumptech.glide.load.DataSource; -+import com.bumptech.glide.load.engine.GlideException; - import com.bumptech.glide.load.model.GlideUrl; - import com.bumptech.glide.request.Request; -+import com.bumptech.glide.request.RequestListener; -+import com.bumptech.glide.request.target.SimpleTarget; -+import com.bumptech.glide.request.target.Target; -+import com.bumptech.glide.request.transition.Transition; - import com.facebook.react.bridge.ReadableMap; - import com.facebook.react.bridge.WritableMap; - import com.facebook.react.bridge.WritableNativeMap; - import com.facebook.react.uimanager.ThemedReactContext; - import com.facebook.react.uimanager.events.RCTEventEmitter; - -+import java.io.File; - import java.util.ArrayList; - import java.util.Collections; - import java.util.List; -@@ -124,9 +133,34 @@ class FastImageViewWithUrl extends AppCompatImageView { - RCTEventEmitter eventEmitter = context.getJSModule(RCTEventEmitter.class); - int viewId = this.getId(); - -- eventEmitter.receiveEvent(viewId, -- FastImageViewManager.REACT_ON_LOAD_START_EVENT, -- new WritableNativeMap()); -+ // Request the URL from cache to see if it exists there and if so pass the cache -+ // path as an argument in the onLoadStart event -+ requestManager -+ .asFile() -+ .load(glideUrl) -+ .onlyRetrieveFromCache(true) -+ .listener(new RequestListener() { -+ @Override -+ public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { -+ WritableNativeMap result = new WritableNativeMap(); -+ result.putNull("cachePath"); -+ eventEmitter.receiveEvent(viewId, -+ FastImageViewManager.REACT_ON_LOAD_START_EVENT, -+ result); -+ return false; -+ } -+ -+ @Override -+ public boolean onResourceReady(File resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { -+ WritableNativeMap result = new WritableNativeMap(); -+ result.putString("cachePath", resource.getAbsolutePath()); -+ eventEmitter.receiveEvent(viewId, -+ FastImageViewManager.REACT_ON_LOAD_START_EVENT, -+ result); -+ return false; -+ } -+ }) -+ .submit(); - } - - if (requestManager != null) { -@@ -148,6 +182,25 @@ class FastImageViewWithUrl extends AppCompatImageView { - builder.listener(new FastImageRequestListener(key)); - - builder.into(this); -+ -+ // Used specifically to handle the `onLoad` event for the image -+ RCTEventEmitter eventEmitter = context.getJSModule(RCTEventEmitter.class); -+ int viewId = this.getId(); -+ requestManager -+ .as(Size.class) -+ .load(imageSource == null ? null : imageSource.getSourceForLoad()) -+ .into(new SimpleTarget() { -+ @Override -+ public void onResourceReady(@NonNull Size resource, @Nullable Transition transition) { -+ WritableMap resourceData = new WritableNativeMap(); -+ resourceData.putInt("width", resource.width); -+ resourceData.putInt("height", resource.height); -+ eventEmitter.receiveEvent(viewId, -+ "onFastImageLoad", -+ resourceData -+ ); -+ } -+ }); - } - } - -diff --git a/node_modules/react-native-fast-image/android/src/main/java/com/dylanvann/fastimage/Size.java b/node_modules/react-native-fast-image/android/src/main/java/com/dylanvann/fastimage/Size.java -new file mode 100644 -index 0000000..2fe8a47 ---- /dev/null -+++ b/node_modules/react-native-fast-image/android/src/main/java/com/dylanvann/fastimage/Size.java -@@ -0,0 +1,6 @@ -+package com.dylanvann.fastimage; -+ -+public class Size { -+ int width; -+ int height; -+} -\ No newline at end of file -diff --git a/node_modules/react-native-fast-image/dist/index.d.ts b/node_modules/react-native-fast-image/dist/index.d.ts -index 5abb7c9..a2672c6 100644 ---- a/node_modules/react-native-fast-image/dist/index.d.ts -+++ b/node_modules/react-native-fast-image/dist/index.d.ts -@@ -27,6 +27,11 @@ export declare type Source = { - priority?: Priority; - cache?: Cache; - }; -+export interface OnLoadStartEvent { -+ nativeEvent: { -+ cachePath: string | null; -+ }; -+} - export interface OnLoadEvent { - nativeEvent: { - width: number; -@@ -57,7 +62,7 @@ export interface FastImageProps extends AccessibilityProps, ViewProps { - defaultSource?: ImageRequireSource; - resizeMode?: ResizeMode; - fallback?: boolean; -- onLoadStart?(): void; -+ onLoadStart?(event: OnLoadStartEvent): void; - onProgress?(event: OnProgressEvent): void; - onLoad?(event: OnLoadEvent): void; - onError?(): void; -diff --git a/node_modules/react-native-fast-image/ios/FastImage/FFFastImageView.m b/node_modules/react-native-fast-image/ios/FastImage/FFFastImageView.m -index f710081..391ef92 100644 ---- a/node_modules/react-native-fast-image/ios/FastImage/FFFastImageView.m -+++ b/node_modules/react-native-fast-image/ios/FastImage/FFFastImageView.m -@@ -54,7 +54,6 @@ - (void) setOnFastImageError: (RCTDirectEventBlock)onFastImageError { - - (void) setOnFastImageLoadStart: (RCTDirectEventBlock)onFastImageLoadStart { - if (_source && !self.hasSentOnLoadStart) { - _onFastImageLoadStart = onFastImageLoadStart; -- onFastImageLoadStart(@{}); - self.hasSentOnLoadStart = YES; - } else { - _onFastImageLoadStart = onFastImageLoadStart; -@@ -188,7 +187,18 @@ - (void) reloadImage { - } - - if (self.onFastImageLoadStart) { -- self.onFastImageLoadStart(@{}); -+ NSString* cachePath = [[SDImageCache sharedImageCache] cachePathForKey:url]; -+ BOOL isCached = [[SDImageCache sharedImageCache] diskImageDataExistsWithKey:url]; -+ if (isCached) { -+ self.onFastImageLoadStart(@{ -+ @"cachePath": cachePath -+ }); -+ } -+ else { -+ self.onFastImageLoadStart(@{ -+ @"cachePath": [NSNull null] -+ }); -+ } - self.hasSentOnLoadStart = YES; - } else { - self.hasSentOnLoadStart = NO; diff --git a/src/components/ImageView/index.native.js b/src/components/ImageView/index.native.js index 11732715b941..508187af2a8c 100644 --- a/src/components/ImageView/index.native.js +++ b/src/components/ImageView/index.native.js @@ -221,6 +221,7 @@ class ImageView extends PureComponent { // due to ImageZoom shouldShowLoadingIndicator ? styles.opacity0 : styles.opacity1, ]} + disableTransformation source={{uri: this.props.url}} isAuthTokenRequired={this.props.isAuthTokenRequired} resizeMode={Image.resizeMode.contain}