Permalink
Browse files

Merge branch 'fjcaetano-feature/prefetch'

  • Loading branch information...
DylanVann committed Jun 20, 2017
2 parents 1d25cb2 + 46e08b4 commit 4e69ddd09908139feda66b283713d2b0efa04522
View
@@ -1,8 +1,15 @@
import React, { PropTypes, Component } from 'react'
import { requireNativeComponent, Image, View } from 'react-native'
import {
requireNativeComponent,
Image,
NativeModules,
View,
} from 'react-native'
const resolveAssetSource = require('react-native/Libraries/Image/resolveAssetSource')
const FastImageViewNativeModule = NativeModules.FastImageView
class FastImage extends Component {
setNativeProps(nativeProps) {
this._root.setNativeProps(nativeProps)
@@ -50,6 +57,10 @@ FastImage.priority = {
high: 'high',
}
FastImage.preload = sources => {
FastImageViewNativeModule.preload(sources)
}
const FastImageSourcePropType = PropTypes.shape({
uri: PropTypes.string,
headers: PropTypes.objectOf(PropTypes.string),
View
@@ -36,6 +36,7 @@ and
- [x] Aggressively cache images.
- [x] Add authorization headers.
- [x] Prioritize images.
- [x] Preload images.
- [x] GIF support.
## Usage
@@ -63,13 +64,13 @@ const YourImage = () =>
## Properties
`source?: object`
### `source?: object`
Source for the remote image to load.
---
`source.uri?: string`
### `source.uri?: string`
Remote url to load the image from. e.g. `'https://facebook.github.io/react/img/logo_og.png'`.
@@ -81,15 +82,15 @@ Headers to load the image with. e.g. `{ Authorization: 'someAuthToken' }`.
---
`source.priority?: enum`
### `source.priority?: enum`
- `FastImage.priority.low` - Low Priority
- `FastImage.priority.normal` **(Default)** - Normal Priority
- `FastImage.priority.high` - High Priority
---
`resizeMode?: enum`
### `resizeMode?: enum`
- `FastImage.resizeMode.contain` **(Default)** - Scale the image uniformly (maintain the image's aspect ratio) so that both dimensions (width and height) of the image will be equal to or less than the corresponding dimension of the view (minus padding).
- `FastImage.resizeMode.cover` - Scale the image uniformly (maintain the image's aspect ratio) so that both dimensions (width and height) of the image will be equal to or larger than the corresponding dimension of the view (minus padding).
@@ -98,16 +99,44 @@ Headers to load the image with. e.g. `{ Authorization: 'someAuthToken' }`.
---
`onLoad?: () => void`
### `onLoad?: () => void`
Called on a successful image fetch.
---
`onError?: () => void`
### `onError?: () => void`
Called on an image fetching error.
---
### `children`
`FastImage` does not currently support children.
Absolute positioning can be used as an alternative.
(This is because `FastImage` supplies a `android.widget.imageview` and not a `android.view.viewgroup`.)
## Static Methods
### `FastImage.preload: (source[]) => void`
Preload images to display later. e.g.
```js
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' },
},
])
```
## Development
```bash
@@ -0,0 +1,71 @@
package com.dylanvann.fastimage;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import com.bumptech.glide.Priority;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.load.model.LazyHeaders;
import com.facebook.react.bridge.NoSuchKeyException;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableMapKeySetIterator;
import java.util.HashMap;
import java.util.Map;
class FastImageViewConverter {
static GlideUrl glideUrl(ReadableMap source) {
final String uriProp = source.getString("uri");
// Get the headers prop and add to glideUrl.
GlideUrl glideUrl;
try {
final ReadableMap headersMap = source.getMap("headers");
ReadableMapKeySetIterator headersIterator = headersMap.keySetIterator();
LazyHeaders.Builder headersBuilder = new LazyHeaders.Builder();
while (headersIterator.hasNextKey()) {
String key = headersIterator.nextKey();
String value = headersMap.getString(key);
headersBuilder.addHeader(key, value);
}
LazyHeaders headers = headersBuilder.build();
glideUrl = new GlideUrl(uriProp, headers);
} catch (NoSuchKeyException e) {
// If there is no headers object.
glideUrl = new GlideUrl(uriProp);
}
return glideUrl;
}
private static Map<String, Priority> REACT_PRIORITY_MAP =
new HashMap<String, Priority>() {{
put("low", Priority.LOW);
put("normal", Priority.NORMAL);
put("high", Priority.HIGH);
}};
static Priority priority(ReadableMap source) {
// Get the priority prop.
String priorityProp = "normal";
try {
priorityProp = source.getString("priority");
} catch (Exception e) {
// Noop.
}
final Priority priority = REACT_PRIORITY_MAP.get(priorityProp);
return priority;
}
private static Map<String, ImageView.ScaleType> REACT_RESIZE_MODE_MAP =
new HashMap<String, ImageView.ScaleType>() {{
put("contain", ScaleType.FIT_CENTER);
put("cover", ScaleType.CENTER_CROP);
put("stretch", ScaleType.FIT_XY);
put("center", ScaleType.CENTER);
}};
public static ScaleType scaleType(String resizeMode) {
if (resizeMode == null) resizeMode = "contain";
final ImageView.ScaleType scaleType = REACT_RESIZE_MODE_MAP.get(resizeMode);
return scaleType;
}
}
@@ -4,25 +4,17 @@
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import com.bumptech.glide.DrawableRequestBuilder;
import com.bumptech.glide.DrawableTypeRequest;
import com.bumptech.glide.Glide;
import com.bumptech.glide.Priority;
import com.bumptech.glide.RequestManager;
import com.bumptech.glide.load.data.DataFetcher;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.load.model.LazyHeaders;
import com.bumptech.glide.load.model.stream.StreamModelLoader;
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.ImageViewTarget;
import com.bumptech.glide.request.target.Target;
import com.bumptech.glide.signature.StringSignature;
import com.facebook.react.bridge.NoSuchKeyException;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableMapKeySetIterator;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeMap;
import com.facebook.react.common.MapBuilder;
@@ -33,9 +25,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import javax.annotation.Nullable;
@@ -49,21 +39,6 @@
private static Drawable TRANSPARENT_DRAWABLE = new ColorDrawable(Color.TRANSPARENT);
private static Map<String, Priority> REACT_PRIORITY_MAP =
new HashMap<String, Priority>() {{
put("low", Priority.LOW);
put("normal", Priority.NORMAL);
put("high", Priority.HIGH);
}};
private static Map<String, ImageView.ScaleType> REACT_RESIZE_MODE_MAP =
new HashMap<String, ImageView.ScaleType>() {{
put("contain", ScaleType.FIT_CENTER);
put("cover", ScaleType.CENTER_CROP);
put("stretch", ScaleType.FIT_XY);
put("center", ScaleType.CENTER);
}};
@Override
public String getName() {
return REACT_CLASS;
@@ -125,51 +100,27 @@ public void setSrc(ImageView view, @Nullable ReadableMap source) {
return;
}
final String uriProp = source.getString("uri");
// Get the headers prop and add to glideUrl.
GlideUrl glideUrl;
try {
final ReadableMap headersMap = source.getMap("headers");
ReadableMapKeySetIterator headersIterator = headersMap.keySetIterator();
LazyHeaders.Builder headersBuilder = new LazyHeaders.Builder();
while (headersIterator.hasNextKey()) {
String key = headersIterator.nextKey();
String value = headersMap.getString(key);
headersBuilder.addHeader(key, value);
}
LazyHeaders headers = headersBuilder.build();
glideUrl = new GlideUrl(uriProp, headers);
} catch (NoSuchKeyException e) {
// If there is no headers object.
glideUrl = new GlideUrl(uriProp);
}
// Get the GlideUrl which contains header info.
final GlideUrl glideUrl = FastImageViewConverter.glideUrl(source);
// Get the priority prop.
String priorityProp = "normal";
try {
priorityProp = source.getString("priority");
} catch (Exception e) {
// Noop.
}
final Priority priority = REACT_PRIORITY_MAP.get(priorityProp);
// Get priority.
final Priority priority = FastImageViewConverter.priority(source);
// Cancel existing request.
Glide.clear(view);
Glide
.with(view.getContext())
.load(glideUrl)
.priority(priority)
.placeholder(TRANSPARENT_DRAWABLE)
.listener(LISTENER)
.into(view);
.with(view.getContext())
.load(glideUrl)
.priority(priority)
.placeholder(TRANSPARENT_DRAWABLE)
.listener(LISTENER)
.into(view);
}
@ReactProp(name = "resizeMode")
public void setResizeMode(ImageView view, String resizeMode) {
if (resizeMode == null) resizeMode = "contain";
final ImageView.ScaleType scaleType = REACT_RESIZE_MODE_MAP.get(resizeMode);
final ImageView.ScaleType scaleType = FastImageViewConverter.scaleType(resizeMode);
view.setScaleType(scaleType);
}
@@ -0,0 +1,54 @@
package com.dylanvann.fastimage;
import android.app.Activity;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import com.bumptech.glide.Glide;
import com.bumptech.glide.Priority;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.model.GlideUrl;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
class FastImageViewModule extends ReactContextBaseJavaModule {
private static final String REACT_CLASS = "FastImageView";
FastImageViewModule(ReactApplicationContext reactContext) {
super(reactContext);
}
@Override
public String getName() {
return REACT_CLASS;
}
private static Drawable TRANSPARENT_DRAWABLE = new ColorDrawable(Color.TRANSPARENT);
@ReactMethod
public void preload(final ReadableArray sources) {
final Activity activity = getCurrentActivity();
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < sources.size(); i++) {
final ReadableMap source = sources.getMap(i);
final GlideUrl glideUrl = FastImageViewConverter.glideUrl(source);
final Priority priority = FastImageViewConverter.priority(source);
Glide
.with(activity.getApplicationContext())
.load(glideUrl)
.priority(priority)
.placeholder(TRANSPARENT_DRAWABLE)
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
.preload();
}
}
});
}
}
@@ -1,5 +1,7 @@
package com.dylanvann.fastimage;
import com.dylanvann.fastimage.FastImageViewModule;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.JavaScriptModule;
@@ -10,10 +12,9 @@
import java.util.List;
public class FastImageViewPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Collections.emptyList();
return Collections.<NativeModule>singletonList(new FastImageViewModule(reactContext));
}
@Override
Oops, something went wrong.

0 comments on commit 4e69ddd

Please sign in to comment.