react-native-fast-image 8.11.0 → 8.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/android/src/main/java/com/dylanvann/fastimage/FastImageGif.java +37 -0
- package/android/src/main/java/com/dylanvann/fastimage/FastImageViewManager.java +5 -0
- package/android/src/main/java/com/dylanvann/fastimage/FastImageViewWithUrl.java +35 -2
- package/dist/index.cjs.js.flow +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js.flow +1 -0
- package/ios/FastImage/FFFastImageView.h +2 -0
- package/ios/FastImage/FFFastImageView.m +20 -1
- package/ios/FastImage/FFFastImageViewManager.m +1 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -196,6 +196,12 @@ How the image is filtered when it's drawn smaller or larger than its size (like
|
|
|
196
196
|
|
|
197
197
|
---
|
|
198
198
|
|
|
199
|
+
### `paused?: boolean`
|
|
200
|
+
|
|
201
|
+
Pauses an animated image (GIF, and animated WebP on iOS) on the frame it's showing; `false` plays it again from there. Each image animates on its own, so pausing one doesn't pause others showing the same file.
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
199
205
|
### `onLoadStart?: () => void`
|
|
200
206
|
|
|
201
207
|
Called when the image starts to load.
|
|
@@ -18,6 +18,7 @@ import com.bumptech.glide.load.resource.bitmap.BitmapResource;
|
|
|
18
18
|
import com.bumptech.glide.load.resource.gif.GifBitmapProvider;
|
|
19
19
|
import com.bumptech.glide.load.resource.gif.GifDrawable;
|
|
20
20
|
|
|
21
|
+
import java.lang.reflect.Field;
|
|
21
22
|
import java.nio.ByteBuffer;
|
|
22
23
|
|
|
23
24
|
// Gives a view its own animation of a GIF. Glide gives every view that shows
|
|
@@ -64,6 +65,42 @@ final class FastImageGif {
|
|
|
64
65
|
return copy;
|
|
65
66
|
}
|
|
66
67
|
|
|
68
|
+
// GifDrawable.start() also starts counting plays again, so a paused GIF
|
|
69
|
+
// would play its whole loop count again when resumed; iOS continues it.
|
|
70
|
+
// The count isn't public: keep it across start() by reflection. A GIF
|
|
71
|
+
// that already finished its plays starts over, as on iOS. Without the
|
|
72
|
+
// fields (another Glide version), it counts again, as start() does.
|
|
73
|
+
@Nullable
|
|
74
|
+
private static final Field LOOP_COUNT = field("loopCount");
|
|
75
|
+
@Nullable
|
|
76
|
+
private static final Field MAX_LOOP_COUNT = field("maxLoopCount");
|
|
77
|
+
|
|
78
|
+
static void resume(GifDrawable gif) {
|
|
79
|
+
if (LOOP_COUNT == null || MAX_LOOP_COUNT == null) {
|
|
80
|
+
gif.start();
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
int played = LOOP_COUNT.getInt(gif);
|
|
85
|
+
int max = MAX_LOOP_COUNT.getInt(gif);
|
|
86
|
+
gif.start();
|
|
87
|
+
if (max == GifDrawable.LOOP_FOREVER || played < max) LOOP_COUNT.setInt(gif, played);
|
|
88
|
+
} catch (IllegalAccessException e) {
|
|
89
|
+
gif.start();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
@Nullable
|
|
94
|
+
private static Field field(String name) {
|
|
95
|
+
try {
|
|
96
|
+
Field field = GifDrawable.class.getDeclaredField(name);
|
|
97
|
+
field.setAccessible(true);
|
|
98
|
+
return field.getType() == int.class ? field : null;
|
|
99
|
+
} catch (Exception e) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
67
104
|
// ByteBufferGifDecoder's.
|
|
68
105
|
private static int sampleSize(GifHeader header, int width, int height) {
|
|
69
106
|
int exact = Math.min(header.getHeight() / height, header.getWidth() / width);
|
|
@@ -99,6 +99,11 @@ class FastImageViewManager extends SimpleViewManager<FastImageViewWithUrl> imple
|
|
|
99
99
|
view.setImageRendering(imageRendering);
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
@ReactProp(name = "paused")
|
|
103
|
+
public void setPaused(FastImageViewWithUrl view, boolean paused) {
|
|
104
|
+
view.setPaused(paused);
|
|
105
|
+
}
|
|
106
|
+
|
|
102
107
|
@ReactProp(name = "resizeMode")
|
|
103
108
|
public void setResizeMode(FastImageViewWithUrl view, String resizeMode) {
|
|
104
109
|
final FastImageViewWithUrl.ScaleType scaleType = FastImageViewConverter.getScaleType(resizeMode);
|
|
@@ -79,8 +79,26 @@ class FastImageViewWithUrl extends AppCompatImageView {
|
|
|
79
79
|
// another view plays it.
|
|
80
80
|
if (mOwnGif != null && getDrawable() == mOwnGif) {
|
|
81
81
|
applyLoopCount(mOwnGif);
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
if (!mPaused) {
|
|
83
|
+
mOwnGif.stop();
|
|
84
|
+
mOwnGif.startFromFirstFrame();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Pauses GIFs on the frame they're showing (the view's own animation).
|
|
90
|
+
private boolean mPaused = false;
|
|
91
|
+
|
|
92
|
+
public void setPaused(boolean paused) {
|
|
93
|
+
if (paused == mPaused) return;
|
|
94
|
+
mPaused = paused;
|
|
95
|
+
if (mOwnGif != null && getDrawable() == mOwnGif) {
|
|
96
|
+
if (paused) {
|
|
97
|
+
mOwnGif.stop();
|
|
98
|
+
} else {
|
|
99
|
+
// Continues the loop count, as on iOS.
|
|
100
|
+
FastImageGif.resume(mOwnGif);
|
|
101
|
+
}
|
|
84
102
|
}
|
|
85
103
|
}
|
|
86
104
|
|
|
@@ -112,12 +130,27 @@ class FastImageViewWithUrl extends AppCompatImageView {
|
|
|
112
130
|
applyLoopCount(own);
|
|
113
131
|
super.onResourceReady(own, transition);
|
|
114
132
|
mOwnGif = own;
|
|
133
|
+
// The target starts it; paused, it waits on its first frame.
|
|
134
|
+
if (mPaused) own.stop();
|
|
115
135
|
return;
|
|
116
136
|
}
|
|
117
137
|
}
|
|
118
138
|
super.onResourceReady(resource, transition);
|
|
119
139
|
}
|
|
120
140
|
|
|
141
|
+
// The target starts animations again when the Activity does: not a
|
|
142
|
+
// paused one, and the view's own GIF continues its loop count (start()
|
|
143
|
+
// would count again).
|
|
144
|
+
@Override
|
|
145
|
+
public void onStart() {
|
|
146
|
+
if (mPaused) return;
|
|
147
|
+
if (mOwnGif != null && getDrawable() == mOwnGif) {
|
|
148
|
+
FastImageGif.resume(mOwnGif);
|
|
149
|
+
} else {
|
|
150
|
+
super.onStart();
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
121
154
|
@Override
|
|
122
155
|
protected void setResource(@Nullable Drawable resource) {
|
|
123
156
|
super.setResource(resource);
|
package/dist/index.cjs.js.flow
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -88,6 +88,12 @@ export interface FastImageProps extends AccessibilityProps, ViewProps {
|
|
|
88
88
|
* pixels, e.g. for pixel art).
|
|
89
89
|
*/
|
|
90
90
|
imageRendering?: 'auto' | 'smooth' | 'pixelated';
|
|
91
|
+
/**
|
|
92
|
+
* Pauses an animated image (GIF, and animated WebP on iOS) on the frame
|
|
93
|
+
* it's showing; `false` plays it again from there. Each image animates on
|
|
94
|
+
* its own, so pausing one doesn't pause others showing the same file.
|
|
95
|
+
*/
|
|
96
|
+
paused?: boolean;
|
|
91
97
|
onLoadStart?(): void;
|
|
92
98
|
onProgress?(event: OnProgressEvent): void;
|
|
93
99
|
onLoad?(event: OnLoadEvent): void;
|
package/dist/index.js.flow
CHANGED
|
@@ -28,6 +28,8 @@
|
|
|
28
28
|
// How the image is filtered when drawn at another size: auto, smooth or
|
|
29
29
|
// pixelated.
|
|
30
30
|
@property (nonatomic, copy) NSString *imageRendering;
|
|
31
|
+
// Pauses animated images on the frame they're showing.
|
|
32
|
+
@property (nonatomic, assign) BOOL paused;
|
|
31
33
|
|
|
32
34
|
@end
|
|
33
35
|
|
|
@@ -85,9 +85,28 @@ static CFTimeInterval FFFEnteredBackgroundAt = 0;
|
|
|
85
85
|
} else if (self.player && [self.image conformsToProtocol: @protocol(SDAnimatedImage)]) {
|
|
86
86
|
self.player.totalLoopCount = [(id<SDAnimatedImage>) self.image animatedImageLoopCount];
|
|
87
87
|
}
|
|
88
|
-
// Apply it to the image that's showing, and play it again
|
|
88
|
+
// Apply it to the image that's showing, and play it again (unless it's
|
|
89
|
+
// paused: then it waits on the first frame).
|
|
89
90
|
if (self.player) {
|
|
90
91
|
[self.player seekToFrameAtIndex: 0 loopCount: 0];
|
|
92
|
+
if (!_paused) {
|
|
93
|
+
[self startAnimating];
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
- (void) setPaused: (BOOL)paused {
|
|
99
|
+
if (_paused == paused) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
_paused = paused;
|
|
103
|
+
// SDAnimatedImageView starts an animated image when it's shown, and again
|
|
104
|
+
// when the view comes back on screen, unless autoPlayAnimatedImage is off.
|
|
105
|
+
// Stopping keeps the frame it's on (resetFrameIndexWhenStopped is off).
|
|
106
|
+
self.autoPlayAnimatedImage = !paused;
|
|
107
|
+
if (paused) {
|
|
108
|
+
[self stopAnimating];
|
|
109
|
+
} else {
|
|
91
110
|
[self startAnimating];
|
|
92
111
|
}
|
|
93
112
|
}
|
|
@@ -20,6 +20,7 @@ RCT_EXPORT_VIEW_PROPERTY(resizeMode, RCTResizeMode)
|
|
|
20
20
|
RCT_EXPORT_VIEW_PROPERTY(recyclingKey, NSString)
|
|
21
21
|
RCT_EXPORT_VIEW_PROPERTY(loopCount, NSInteger)
|
|
22
22
|
RCT_EXPORT_VIEW_PROPERTY(imageRendering, NSString)
|
|
23
|
+
RCT_EXPORT_VIEW_PROPERTY(paused, BOOL)
|
|
23
24
|
RCT_EXPORT_VIEW_PROPERTY(onFastImageLoadStart, RCTDirectEventBlock)
|
|
24
25
|
RCT_EXPORT_VIEW_PROPERTY(onFastImageProgress, RCTDirectEventBlock)
|
|
25
26
|
RCT_EXPORT_VIEW_PROPERTY(onFastImageError, RCTDirectEventBlock)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-fast-image",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.12.0",
|
|
4
4
|
"description": "🚩 FastImage, performant React Native image component.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cache",
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
"@types/react": "^17.0.14",
|
|
52
52
|
"@types/react-native": "^0.69.5",
|
|
53
53
|
"@types/react-test-renderer": "^17.0.1",
|
|
54
|
+
"conventional-changelog-angular": "8.3.1",
|
|
54
55
|
"maestro-runner": "1.1.27",
|
|
55
56
|
"odiff-bin": "^4.5.0",
|
|
56
57
|
"oxfmt": "0.70.0",
|