Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Added fade animation support #979

Open
wants to merge 39 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
ead60db
Add onProgress and onComplete callbacks for `preload` both on Android…
doomsower Aug 29, 2018
5c11dec
Merge branch 'master' into preload_callbacks
doomsower Jan 19, 2019
5f9b91c
Merge remote-tracking branch 'banana/preload_callbacks' into feature/…
Mickagd Mar 26, 2019
179af4c
fix flow
Mickagd Mar 28, 2019
29b01a9
fix: an empty sources array never called onComplete
Elindorath Apr 18, 2019
39d4cd5
Merge pull request #1 from DylanVann/master
Mickagd Jun 19, 2019
4c09121
Merge branch 'master' into feature/preload-callbacks
Mickagd Jun 19, 2019
40cb5b8
fix lint
Mickagd Jun 19, 2019
c86abda
update swebimage
Mickagd Jun 19, 2019
1d93c0d
Merge pull request #2 from DylanVann/master
joan-saum Oct 28, 2019
0f67ddb
Merge branch 'master' into feature/preload-callbacks
Nov 4, 2019
3812d45
Merge remote-tracking branch 'upstream/master' into feature/preload-c…
Aug 18, 2021
6dd7261
fix: revert FastImagePreloaderModule class to FastImageViewModule + a…
Aug 18, 2021
70fe646
fix lint
Aug 18, 2021
7dffb00
fix NativeEventEmitter mock in test
Aug 18, 2021
7dcb4ae
fix NativeEventEmitter mock in test
Aug 18, 2021
d7ea691
turn preloadermanager.js to typescript file
Aug 18, 2021
440ee83
fix lint + add listener to FastImageViewModule.java
Aug 19, 2021
2af79e5
bind context to listeners
Aug 19, 2021
f8d13ec
add SDWebImageDownloader.h import in FFFastImagePreloaderManager.m file
Aug 20, 2021
bbe6c9d
Merge pull request #4 from Sparted/feature/preload-callbacks-fetch-up…
Mickagd Aug 20, 2021
0ee6e1f
Merge branch 'main' into feature/preload-callbacks
Flictuum Jan 25, 2022
4f88f36
Import FastImageViewNativeModule into index file
nicomontanari Feb 14, 2022
a5a45e9
Update FastImageViewNativeModule variable
nicomontanari Jan 16, 2023
1d13dcd
Added animation support & Added fade animation
geroale Mar 6, 2023
519dba7
Added animation support & Added fade animation
geroale Mar 6, 2023
bd8ffd1
Revert "Added animation support & Added fade animation"
geroale Mar 6, 2023
be64a04
Added animation support & Added fade animation
geroale Mar 6, 2023
7a771d5
Update README.md
geroale Mar 6, 2023
f5847b3
Merge remote-tracking branch 'upstream/main'
nicomontanari Jul 17, 2023
fbb6199
Update android/src/main/java/com/dylanvann/fastimage/FastImagePreload…
nicomontanari Oct 12, 2023
242add2
Update preload manager references
nicomontanari Oct 17, 2023
4f70201
Removed fade animation for unchanged URI
andreamorandi Dec 21, 2023
e8bdefd
Fixed package name
andreamorandi Dec 21, 2023
21bd55f
Bumped version
andreamorandi Dec 21, 2023
4a70860
Merge remote-tracking branch 'preload/master'
geroale Oct 31, 2024
2e335cf
Update package.json
geroale Oct 31, 2024
9b0076d
Bumped version
geroale Oct 31, 2024
336baa5
Update FastImageViewWithUrl.java
geroale Nov 4, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 18 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,13 @@ Headers to load the image with. e.g. `{ Authorization: 'someAuthToken' }`.

---

### `animation?: enum`

- `FastImage.animation.none` **(Default)** - No animation in image loading.
- `FastImage.animation.fade` - Fade in animation in image loading.

---

### `onLoadStart?: () => void`

Called when the image starts to load.
Expand Down Expand Up @@ -212,21 +219,25 @@ If supplied, changes the color of all the non-transparent pixels to the given co

## Static Methods

### `FastImage.preload: (source[]) => void`
### `FastImage.preload: (source[], onProgress?, onComplete?) => void`

Preload images to display later. e.g.

```js
FastImage.preload([
FastImage.preload(
[
{
uri: 'https://facebook.github.io/react/img/logo_og.png',
headers: { Authorization: 'someAuthToken' },
uri: 'https://facebook.github.io/react/img/logo_og.png',
headers: { Authorization: 'someAuthToken' },
},
{
uri: 'https://facebook.github.io/react/img/logo_og.png',
headers: { Authorization: 'someAuthToken' },
uri: 'https://facebook.github.io/react/img/logo_og.png',
headers: { Authorization: 'someAuthToken' },
},
])
],
(finished, total) => console.log(`Preloaded ${finished}/${total} images`),
(finished, skipped) => console.log(`Completed. Failed to load ${skipped}/${finished} images`),
)
```

### `FastImage.clearMemoryCache: () => Promise<void>`
Expand Down
4 changes: 2 additions & 2 deletions RNFastImage.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ Pod::Spec.new do |s|
s.version = package['version']
s.summary = package['description']
s.authors = { "Dylan Vann" => "[email protected]" }
s.homepage = "https://github.com/DylanVann/react-native-fast-image#readme"
s.homepage = "https://github.com/Spicy-Sparks/react-native-fast-image#readme"
s.license = "MIT"
s.platforms = { :ios => "8.0", :tvos => "9.0" }
s.framework = 'UIKit'
s.requires_arc = true
s.source = { :git => "https://github.com/DylanVann/react-native-fast-image.git", :tag => "v#{s.version}" }
s.source = { :git => "https://github.com/Spicy-Sparks/react-native-fast-image.git", :tag => "v#{s.version}" }
s.source_files = "ios/**/*.{h,m}"

s.dependency 'React-Core'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.dylanvann.fastimage;

public enum FastImageAnimation {
FADE,
NONE
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.dylanvann.fastimage;

import androidx.annotation.Nullable;
import android.util.Log;

import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.Target;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;

import java.io.File;

class FastImagePreloaderListener implements RequestListener<File> {
private static final String LOG = "[FFFastImage]";
private static final String EVENT_PROGRESS = "fffastimage-progress";
private static final String EVENT_COMPLETE = "fffastimage-complete";

private final ReactApplicationContext reactContext;
private final int id;
private final int total;
private int succeeded = 0;
private int failed = 0;

public FastImagePreloaderListener(ReactApplicationContext reactContext, int id, int totalImages) {
this.id = id;
this.reactContext = reactContext;
this.total = totalImages;
}

@Override
public boolean onLoadFailed(@Nullable GlideException e, Object o, Target<File> target, boolean b) {
// o is whatever was passed to .load() = GlideURL, String, etc.
Log.d(LOG, "Preload failed: " + o.toString());
this.failed++;
this.dispatchProgress();
return false;
}

@Override
public boolean onResourceReady(File file, Object o, Target<File> target, DataSource dataSource, boolean b) {
// o is whatever was passed to .load() = GlideURL, String, etc.
Log.d(LOG, "Preload succeeded: " + o.toString());
this.succeeded++;
this.dispatchProgress();
return false;
}

private void maybeDispatchComplete() {
if (this.failed + this.succeeded >= this.total) {
WritableMap params = Arguments.createMap();
params.putInt("id", this.id);
params.putInt("finished", this.succeeded + this.failed);
params.putInt("skipped", this.failed);
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(EVENT_COMPLETE, params);
}
}

private void dispatchProgress() {
WritableMap params = Arguments.createMap();
params.putInt("id", this.id);
params.putInt("finished", this.succeeded + this.failed);
params.putInt("total", this.total);
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(EVENT_PROGRESS, params);
this.maybeDispatchComplete();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ class FastImageViewConverter {
put("center", ScaleType.CENTER_INSIDE);
}};

private static final Map<String, FastImageAnimation> FAST_IMAGE_ANIMATION_MAP =
new HashMap<String, FastImageAnimation>() {{
put("fade", FastImageAnimation.FADE);
put("none", FastImageAnimation.NONE);
}};

// Resolve the source uri to a file path that android understands.
static @Nullable
FastImageSource getImageSource(Context context, @Nullable ReadableMap source) {
Expand Down Expand Up @@ -133,6 +139,10 @@ static ScaleType getScaleType(String propValue) {
return getValue("resizeMode", "cover", FAST_IMAGE_RESIZE_MODE_MAP, propValue);
}

static FastImageAnimation getAnimation(String propValue) {
return getValue("animation", "none", FAST_IMAGE_ANIMATION_MAP, propValue);
}

private static <T> T getValue(String propName, String defaultPropValue, Map<String, T> map, String propValue) {
if (propValue == null) propValue = defaultPropValue;
T value = map.get(propValue);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ public void setResizeMode(FastImageViewWithUrl view, String resizeMode) {
view.setScaleType(scaleType);
}

@ReactProp(name = "animation")
public void setAnimation(FastImageViewWithUrl view, String animation) {
final FastImageAnimation animationType = FastImageViewConverter.getAnimation(animation);
view.setAnimation(animationType);
}

@Override
public void onDropViewInstance(@NonNull FastImageViewWithUrl view) {
// This will cancel existing requests.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@

class FastImageViewModule extends ReactContextBaseJavaModule {

private static final String REACT_CLASS = "FastImageView";
private static final String REACT_CLASS = "FastImagePreloaderManager";
private int preloaders = 0;

FastImageViewModule(ReactApplicationContext reactContext) {
super(reactContext);
Expand All @@ -29,18 +30,25 @@ public String getName() {
}

@ReactMethod
public void preload(final ReadableArray sources) {
public void createPreloader(Promise promise) {
promise.resolve(preloaders++);
}

@ReactMethod
public void preload(final int preloaderId, final ReadableArray sources) {
final Activity activity = getCurrentActivity();
if (activity == null) return;
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
FastImagePreloaderListener preloader = new FastImagePreloaderListener(getReactApplicationContext(), preloaderId, sources.size());
for (int i = 0; i < sources.size(); i++) {
final ReadableMap source = sources.getMap(i);
final FastImageSource imageSource = FastImageViewConverter.getImageSource(activity, source);

Glide
.with(activity.getApplicationContext())
.downloadOnly()
// This will make this work for remote and local images. e.g.
// - file:///
// - content://
Expand All @@ -51,6 +59,7 @@ public void run() {
imageSource.isBase64Resource() ? imageSource.getSource() :
imageSource.isResource() ? imageSource.getUri() : imageSource.getGlideUrl()
)
.listener(preloader)
.apply(FastImageViewConverter.getOptions(activity, imageSource, source))
.preload();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.bumptech.glide.RequestBuilder;
import com.bumptech.glide.RequestManager;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
import com.bumptech.glide.request.Request;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
Expand All @@ -23,13 +24,16 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import javax.annotation.Nonnull;

class FastImageViewWithUrl extends AppCompatImageView {
private boolean mNeedsReload = false;
private ReadableMap mSource = null;
private ReadableMap mPreviousSource = null;
private Drawable mDefaultSource = null;
private FastImageAnimation mAnimation = FastImageAnimation.NONE;

public GlideUrl glideUrl;

Expand All @@ -47,6 +51,10 @@ public void setDefaultSource(@Nullable Drawable source) {
mDefaultSource = source;
}

public void setAnimation(FastImageAnimation animation) {
mAnimation = animation;
}

private boolean isNullOrEmpty(final String url) {
return url == null || url.trim().isEmpty();
}
Expand All @@ -73,6 +81,8 @@ public void onAfterUpdate(

// Clear the image.
setImageDrawable(null);

mPreviousSource = null;
return;
}

Expand All @@ -95,6 +105,8 @@ public void onAfterUpdate(
}
// Clear the image.
setImageDrawable(null);

mPreviousSource = null;
return;
}

Expand Down Expand Up @@ -144,11 +156,16 @@ public void onAfterUpdate(
.placeholder(mDefaultSource) // show until loaded
.fallback(mDefaultSource)); // null will not be treated as error

if(mAnimation == FastImageAnimation.FADE && (mPreviousSource == null || !Objects.equals(mSource.getString("uri"), mPreviousSource.getString("uri")))) {
builder = builder.transition(DrawableTransitionOptions.withCrossFade());
}

if (key != null)
builder.listener(new FastImageRequestListener(key));

builder.into(this);
}
mPreviousSource = mSource;
}

public void clearView(@Nullable RequestManager requestManager) {
Expand Down
10 changes: 10 additions & 0 deletions ios/FastImage.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
7547098A212F3BE70040708C /* FFFastImagePreloaderManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FFFastImagePreloaderManager.h; sourceTree = "<group>"; };
75470990212F3C590040708C /* FFFastImagePreloaderManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FFFastImagePreloaderManager.m; sourceTree = "<group>"; };
75470992212F3F9A0040708C /* FFFastImagePreloader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FFFastImagePreloader.h; sourceTree = "<group>"; };
75470993212F409B0040708C /* FFFastImagePreloader.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FFFastImagePreloader.m; sourceTree = "<group>"; };
A287971D1DE0C0A60081BDFA /* libFastImage.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libFastImage.a; sourceTree = BUILT_PRODUCTS_DIR; };
FCFB25371EA5562700F59778 /* FFFastImageSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FFFastImageSource.h; sourceTree = "<group>"; };
FCFB25381EA5562700F59778 /* FFFastImageSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FFFastImageSource.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -149,6 +153,10 @@
FCFB253C1EA5562700F59778 /* FFFastImageViewManager.m */,
FCFB253D1EA5562700F59778 /* RCTConvert+FFFastImage.h */,
FCFB253E1EA5562700F59778 /* RCTConvert+FFFastImage.m */,
7547098A212F3BE70040708C /* FFFastImagePreloaderManager.h */,
75470990212F3C590040708C /* FFFastImagePreloaderManager.m */,
75470992212F3F9A0040708C /* FFFastImagePreloader.h */,
75470993212F409B0040708C /* FFFastImagePreloader.m */,
);
path = FastImage;
sourceTree = "<group>";
Expand Down Expand Up @@ -261,10 +269,12 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
75470994212F409B0040708C /* FFFastImagePreloader.m in Sources */,
FCFB25411EA5562700F59778 /* FFFastImageViewManager.m in Sources */,
FCFB25421EA5562700F59778 /* RCTConvert+FFFastImage.m in Sources */,
FCFB25401EA5562700F59778 /* FFFastImageView.m in Sources */,
FCFB253F1EA5562700F59778 /* FFFastImageSource.m in Sources */,
75470991212F3C590040708C /* FFFastImagePreloaderManager.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
9 changes: 9 additions & 0 deletions ios/FastImage/FFFastImagePreloader.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#import "FFFastImageSource.h"
#import <Foundation/Foundation.h>
#import <SDWebImage/SDWebImagePrefetcher.h>

@interface FFFastImagePreloader : SDWebImagePrefetcher

@property (nonatomic, readonly) NSNumber* id;

@end
16 changes: 16 additions & 0 deletions ios/FastImage/FFFastImagePreloader.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#import "FFFastImagePreloader.h"
#import "FFFastImageSource.h"

static int instanceCounter = 0;

@implementation FFFastImagePreloader

-(instancetype) init {
if (self = [super init]) {
instanceCounter ++;
_id = [NSNumber numberWithInt:instanceCounter];
}
return self;
}

@end
7 changes: 7 additions & 0 deletions ios/FastImage/FFFastImagePreloaderManager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
#import <SDWebImage/SDWebImagePrefetcher.h>

@interface FFFastImagePreloaderManager : RCTEventEmitter <RCTBridgeModule, SDWebImagePrefetcherDelegate>

@end
Loading