Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
57 changes: 22 additions & 35 deletions PhotoView.android.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, {Component, PropTypes} from 'react';
import {requireNativeComponent, View} from 'react-native';
import ViewPropTypes from 'react-native/Libraries/Components/View/ViewPropTypes';

const resolveAssetSource = require('react-native/Libraries/Image/resolveAssetSource');

Expand Down Expand Up @@ -29,51 +28,39 @@ export default class PhotoView extends Component {
onLoadStart: PropTypes.func,
onLoad: PropTypes.func,
onLoadEnd: PropTypes.func,
onProgress: PropTypes.func,
onTap: PropTypes.func,
onViewTap: PropTypes.func,
onScale: PropTypes.func,
...ViewPropTypes
};
...View.propTypes
};

render() {
const source = resolveAssetSource(this.props.source);
var loadingIndicatorSource = resolveAssetSource(this.props.loadingIndicatorSource);
render() {
const source = resolveAssetSource(this.props.source);
var loadingIndicatorSource = resolveAssetSource(this.props.loadingIndicatorSource);

if (source && source.uri === '') {
console.warn('source.uri should not be an empty string');
}
if (source && source.uri === '') {
console.warn('source.uri should not be an empty string');
}

if (this.props.src) {
console.warn('The <PhotoView> component requires a `source` property rather than `src`.');
}
if (this.props.src) {
console.warn('The <PhotoView> component requires a `source` property rather than `src`.');
}

if (source && source.uri) {
var {onLoadStart, onLoad, onLoadEnd} = this.props;
if (source && source.uri) {
var {onLoadStart, onLoad, onLoadEnd} = this.props;

var nativeProps = {
onPhotoViewerLoadStart: this.props.onLoadStart,
onPhotoViewerLoad: this.props.onLoad,
onPhotoViewerLoadEnd: this.props.onLoadEnd,
onPhotoViewerTap: this.props.onTap,
onPhotoViewerViewTap: this.props.onViewTap,
onPhotoViewerScale: this.props.onScale,
var nativeProps = {
...this.props,
shouldNotifyLoadEvents: !!(onLoadStart || onLoad || onLoadEnd),
src: source.uri,
loadingIndicatorSrc: loadingIndicatorSource ? loadingIndicatorSource.uri : null,
};

delete nativeProps.onLoadStart;
delete nativeProps.onLoad;
delete nativeProps.onLoadEnd;
delete nativeProps.onTap;
delete nativeProps.onViewTap;
delete nativeProps.onScale;
shouldNotifyLoadEvents: !!(onLoadStart || onProgress || onLoad || onLoadEnd),
src: source.uri,
loadingIndicatorSrc: loadingIndicatorSource ? loadingIndicatorSource.uri : null,
};

return <PhotoViewAndroid {...nativeProps} />
}
return null
return <PhotoViewAndroid {...nativeProps} />
}
return null
}
}

var cfg = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import java.lang.annotation.RetentionPolicy;

public class ImageEvent extends Event<ImageEvent> {
@IntDef({ON_ERROR, ON_LOAD, ON_LOAD_END, ON_LOAD_START, ON_TAP, ON_VIEW_TAP, ON_SCALE})
@IntDef({ON_ERROR, ON_LOAD, ON_LOAD_END, ON_LOAD_START, ON_TAP, ON_VIEW_TAP, ON_SCALE, ON_PROGRESS})
@Retention(RetentionPolicy.SOURCE)
@interface ImageEventType {}

Expand All @@ -29,6 +29,7 @@ public class ImageEvent extends Event<ImageEvent> {
public static final int ON_TAP = 5;
public static final int ON_VIEW_TAP = 6;
public static final int ON_SCALE = 7;
public static final int ON_PROGRESS = 8;

private final int mEventType;
private WritableMap mMap;
Expand All @@ -55,6 +56,8 @@ public static String eventNameForType(@ImageEventType int eventType) {
return "topViewTap";
case ON_SCALE:
return "topScale";
case ON_PROGRESS:
return "topProgress";
default:
throw new IllegalStateException("Invalid image event: " + Integer.toString(eventType));
}
Expand Down
86 changes: 65 additions & 21 deletions android/src/main/java/com/reactnative/photoview/PhotoView.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.reactnative.photoview;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
Expand All @@ -16,7 +18,6 @@
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.common.SystemClock;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.events.EventDispatcher;
import me.relex.photodraweeview.OnPhotoTapListener;
Expand Down Expand Up @@ -72,7 +73,7 @@ public void setLoadingIndicatorSource(@Nullable String name,
ResourceDrawableIdHelper resourceDrawableIdHelper) {
Drawable drawable = resourceDrawableIdHelper.getResourceDrawable(getContext(), name);
mLoadingImageDrawable =
drawable != null ? (Drawable) new AutoRotateDrawable(drawable, 1000) : null;
drawable != null ? (Drawable) new AutoRotateDrawable(drawable, 1000) : null;
mIsDirty = true;
}

Expand All @@ -86,26 +87,26 @@ public void setShouldNotifyLoadEvents(boolean shouldNotify) {
mControllerListener = null;
} else {
final EventDispatcher eventDispatcher = ((ReactContext) getContext())
.getNativeModule(UIManagerModule.class).getEventDispatcher();
.getNativeModule(UIManagerModule.class).getEventDispatcher();
mControllerListener = new BaseControllerListener<ImageInfo>() {
@Override
public void onSubmit(String id, Object callerContext) {
eventDispatcher.dispatchEvent(
new ImageEvent(getId(), ImageEvent.ON_LOAD_START)
new ImageEvent(getId(), ImageEvent.ON_LOAD_START)
);
}

@Override
public void onFinalImageSet(
String id,
@Nullable final ImageInfo imageInfo,
@Nullable Animatable animatable) {
String id,
@Nullable final ImageInfo imageInfo,
@Nullable Animatable animatable) {
if (imageInfo != null) {
eventDispatcher.dispatchEvent(
new ImageEvent(getId(), ImageEvent.ON_LOAD)
new ImageEvent(getId(), ImageEvent.ON_LOAD)
);
eventDispatcher.dispatchEvent(
new ImageEvent(getId(), ImageEvent.ON_LOAD_END)
new ImageEvent(getId(), ImageEvent.ON_LOAD_END)
);
update(imageInfo.getWidth(), imageInfo.getHeight());
}
Expand All @@ -114,10 +115,10 @@ public void onFinalImageSet(
@Override
public void onFailure(String id, Throwable throwable) {
eventDispatcher.dispatchEvent(
new ImageEvent(getId(), ImageEvent.ON_ERROR)
new ImageEvent(getId(), ImageEvent.ON_ERROR)
);
eventDispatcher.dispatchEvent(
new ImageEvent(getId(), ImageEvent.ON_LOAD_END)
new ImageEvent(getId(), ImageEvent.ON_LOAD_END)
);
}
};
Expand All @@ -131,17 +132,18 @@ public void maybeUpdateView(@NonNull PipelineDraweeControllerBuilder builder) {
}

GenericDraweeHierarchy hierarchy = getHierarchy();
hierarchy.setProgressBarImage(new ImageLoadingDrawable());
if (mLoadingImageDrawable != null) {
hierarchy.setPlaceholderImage(mLoadingImageDrawable, ScalingUtils.ScaleType.CENTER);
}
hierarchy.setFadeDuration(
mFadeDurationMs >= 0
? mFadeDurationMs
: mIsLocalImage ? 0 : REMOTE_IMAGE_FADE_DURATION_MS);
mFadeDurationMs >= 0
? mFadeDurationMs
: mIsLocalImage ? 0 : REMOTE_IMAGE_FADE_DURATION_MS);
setHierarchy(hierarchy);

mDraweeControllerBuilder = builder;
mDraweeControllerBuilder.setUri(mUri);
mDraweeControllerBuilder.setAutoPlayAnimations(true);
mDraweeControllerBuilder.setOldController(getController());
mDraweeControllerBuilder.setControllerListener(new BaseControllerListener<ImageInfo>() {
@Override
Expand All @@ -166,17 +168,16 @@ public void onFinalImageSet(String id, ImageInfo imageInfo, Animatable animatabl

private void setViewCallbacks() {
final EventDispatcher eventDispatcher = ((ReactContext) getContext())
.getNativeModule(UIManagerModule.class).getEventDispatcher();
.getNativeModule(UIManagerModule.class).getEventDispatcher();

setOnPhotoTapListener(new OnPhotoTapListener() {
@Override
public void onPhotoTap(View view, float x, float y) {
WritableMap scaleChange = Arguments.createMap();
scaleChange.putDouble("x", x);
scaleChange.putDouble("y", y);
scaleChange.putDouble("scale", PhotoView.this.getScale());
eventDispatcher.dispatchEvent(
new ImageEvent(getId(), ImageEvent.ON_TAP).setExtras(scaleChange)
new ImageEvent(getId(), ImageEvent.ON_TAP).setExtras(scaleChange)
);
}
});
Expand All @@ -185,12 +186,11 @@ public void onPhotoTap(View view, float x, float y) {
@Override
public void onScaleChange(float scaleFactor, float focusX, float focusY) {
WritableMap scaleChange = Arguments.createMap();
scaleChange.putDouble("scale", PhotoView.this.getScale());
scaleChange.putDouble("scaleFactor", scaleFactor);
scaleChange.putDouble("focusX", focusX);
scaleChange.putDouble("focusY", focusY);
eventDispatcher.dispatchEvent(
new ImageEvent(getId(), ImageEvent.ON_SCALE).setExtras(scaleChange)
new ImageEvent(getId(), ImageEvent.ON_SCALE).setExtras(scaleChange)
);
}
});
Expand All @@ -202,9 +202,53 @@ public void onViewTap(View view, float x, float y) {
scaleChange.putDouble("x", x);
scaleChange.putDouble("y", y);
eventDispatcher.dispatchEvent(
new ImageEvent(getId(), ImageEvent.ON_VIEW_TAP).setExtras(scaleChange)
new ImageEvent(getId(), ImageEvent.ON_TAP).setExtras(scaleChange)
);
}
});
}

class ImageLoadingDrawable extends Drawable {

private final EventDispatcher eventDispatcher;

public ImageLoadingDrawable() {
eventDispatcher = ((ReactContext) getContext())
.getNativeModule(UIManagerModule.class).getEventDispatcher();
}

@Override
public void draw(Canvas canvas) {

}

@Override
protected boolean onLevelChange(int level) {
if (level > 0 && level < 10000) {

WritableMap progress = Arguments.createMap();
progress.putDouble("loaded", level);
progress.putDouble("total", 10000);
eventDispatcher.dispatchEvent(
new ImageEvent(getId(), ImageEvent.ON_PROGRESS).setExtras(progress)
);
return true;
} else {
return false;
}
}

@Override
public void setAlpha(int alpha) {
}

@Override
public void setColorFilter(ColorFilter cf) {
}

@Override
public int getOpacity() {
return 0;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package com.reactnative.photoview;

import android.widget.ImageView.ScaleType;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.backends.pipeline.PipelineDraweeControllerBuilder;
import com.facebook.drawee.drawable.ScalingUtils;
import com.facebook.drawee.generic.GenericDraweeHierarchy;
import com.facebook.react.bridge.ReactApplicationContext;
Expand Down Expand Up @@ -112,12 +110,13 @@ public void setScaleType(PhotoView view, String scaleType) {
public @Nullable
Map getExportedCustomDirectEventTypeConstants() {
return MapBuilder.of(
ImageEvent.eventNameForType(ImageEvent.ON_LOAD_START), MapBuilder.of("registrationName", "onPhotoViewerLoadStart"),
ImageEvent.eventNameForType(ImageEvent.ON_LOAD), MapBuilder.of("registrationName", "onPhotoViewerLoad"),
ImageEvent.eventNameForType(ImageEvent.ON_LOAD_END), MapBuilder.of("registrationName", "onPhotoViewerLoadEnd"),
ImageEvent.eventNameForType(ImageEvent.ON_TAP), MapBuilder.of("registrationName", "onPhotoViewerTap"),
ImageEvent.eventNameForType(ImageEvent.ON_VIEW_TAP), MapBuilder.of("registrationName", "onPhotoViewerViewTap"),
ImageEvent.eventNameForType(ImageEvent.ON_SCALE), MapBuilder.of("registrationName", "onPhotoViewerScale")
ImageEvent.eventNameForType(ImageEvent.ON_LOAD_START), MapBuilder.of("registrationName", "onLoadStart"),
ImageEvent.eventNameForType(ImageEvent.ON_LOAD), MapBuilder.of("registrationName", "onLoad"),
ImageEvent.eventNameForType(ImageEvent.ON_LOAD_END), MapBuilder.of("registrationName", "onLoadEnd"),
ImageEvent.eventNameForType(ImageEvent.ON_TAP), MapBuilder.of("registrationName", "onTap"),
ImageEvent.eventNameForType(ImageEvent.ON_VIEW_TAP), MapBuilder.of("registrationName", "onViewTap"),
ImageEvent.eventNameForType(ImageEvent.ON_SCALE), MapBuilder.of("registrationName", "onScale"),
ImageEvent.eventNameForType(ImageEvent.ON_PROGRESS), MapBuilder.of("registrationName", "onProgress")
);
}

Expand Down