diff --git a/PhotoView.android.js b/PhotoView.android.js index ac3d3bc..f2ea50a 100644 --- a/PhotoView.android.js +++ b/PhotoView.android.js @@ -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'); @@ -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 component requires a `source` property rather than `src`.'); - } + if (this.props.src) { + console.warn('The 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 - } - return null + return } + return null +} } var cfg = { diff --git a/android/src/main/java/com/reactnative/photoview/ImageEvent.java b/android/src/main/java/com/reactnative/photoview/ImageEvent.java index 95c8345..2b38280 100644 --- a/android/src/main/java/com/reactnative/photoview/ImageEvent.java +++ b/android/src/main/java/com/reactnative/photoview/ImageEvent.java @@ -18,7 +18,7 @@ import java.lang.annotation.RetentionPolicy; public class ImageEvent extends Event { - @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 {} @@ -29,6 +29,7 @@ public class ImageEvent extends Event { 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; @@ -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)); } diff --git a/android/src/main/java/com/reactnative/photoview/PhotoView.java b/android/src/main/java/com/reactnative/photoview/PhotoView.java index e18b11a..e2f2b7b 100644 --- a/android/src/main/java/com/reactnative/photoview/PhotoView.java +++ b/android/src/main/java/com/reactnative/photoview/PhotoView.java @@ -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; @@ -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; @@ -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; } @@ -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() { @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()); } @@ -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) ); } }; @@ -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() { @Override @@ -166,7 +168,7 @@ 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 @@ -174,9 +176,8 @@ 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) ); } }); @@ -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) ); } }); @@ -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; + } + } } diff --git a/android/src/main/java/com/reactnative/photoview/PhotoViewManager.java b/android/src/main/java/com/reactnative/photoview/PhotoViewManager.java index 4ab6e7e..c7f6824 100644 --- a/android/src/main/java/com/reactnative/photoview/PhotoViewManager.java +++ b/android/src/main/java/com/reactnative/photoview/PhotoViewManager.java @@ -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; @@ -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") ); }