From 9668ae2b97bb056d7fabd177b527ac1cc481f71b Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Wed, 12 Apr 2023 16:51:16 +0300 Subject: [PATCH 1/2] Revert "Fix/large images android" --- android/app/src/main/AndroidManifest.xml | 2 - package-lock.json | 8 +- package.json | 2 +- patches/react-native-fast-image+8.6.3.patch | 300 ++++++++++++++++++++ src/components/ImageView/index.native.js | 1 - 5 files changed, 303 insertions(+), 10 deletions(-) create mode 100644 patches/react-native-fast-image+8.6.3.patch diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 07214d27c471..514f471bf8e4 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -10,8 +10,6 @@ { ++ ++ @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 508187af2a8c..11732715b941 100644 --- a/src/components/ImageView/index.native.js +++ b/src/components/ImageView/index.native.js @@ -221,7 +221,6 @@ 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} From 4002fde24dbb0e5dd4ef3ddf817a57f4c75fa72b Mon Sep 17 00:00:00 2001 From: Jules Rosser Date: Tue, 16 May 2023 15:45:01 +0100 Subject: [PATCH 2/2] make it clear that hardware accellaration should not be disabled --- android/app/src/main/AndroidManifest.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 514f471bf8e4..8d7d6af2a609 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -8,8 +8,10 @@ +