UNPKG

@nativescript-community/ui-image

Version:

Advanced and efficient image display plugin which uses Fresco (Android) and SDWebImage (iOS) to implement caching, placeholders, image effects, and much more.

785 lines 30.6 kB
var _a, _b, _c, _d; export * from './image-common'; import { ImageAsset, ImageSource, Trace, knownFolders, path } from '@nativescript/core'; import { android as androidApp } from '@nativescript/core/application'; import { isString } from '@nativescript/core/utils/types'; import { RESOURCE_PREFIX, ad, isFileOrResourcePath, isFontIconURI } from '@nativescript/core/utils/utils'; import { CLog, CLogTypes, EventData, ImageBase, ScaleType } from './image-common'; let initialized = false; let initializeConfig; export function initialize(config) { if (!initialized) { const context = androidApp.context; if (!context) { initializeConfig = config; return; } const builder = com.facebook.imagepipeline.core.ImagePipelineConfig.newBuilder(context); if (config && config.isDownsampleEnabled) { builder.setDownsampleEnabled(true); } if (config && config.leakTracker) { builder.setCloseableReferenceLeakTracker(config.leakTracker); } const imagePipelineConfig = builder.build(); com.facebook.drawee.backends.pipeline.Fresco.initialize(context, imagePipelineConfig); initialized = true; initializeConfig = null; } } export function getImagePipeline() { if (androidApp) { const nativePipe = com.facebook.drawee.backends.pipeline.Fresco.getImagePipeline(); const imagePineLine = new ImagePipeline(); imagePineLine.android = nativePipe; return imagePineLine; } return null; } export function shutDown() { if (!initialized) { return; } initialized = false; com.facebook.drawee.view.SimpleDraweeView.shutDown(); com.facebook.drawee.backends.pipeline.Fresco.shutDown(); } function getUri(src) { let uri; let imagePath; if (src instanceof ImageAsset) { imagePath = src.android; } else { imagePath = src; } if (isFileOrResourcePath(imagePath)) { const res = ad.getApplicationContext().getResources(); if (!res) { return null; } if (imagePath.indexOf(RESOURCE_PREFIX) === 0) { const resName = imagePath.substr(RESOURCE_PREFIX.length); const identifier = res.getIdentifier(resName, 'drawable', ad.getApplication().getPackageName()); if (0 < identifier) { uri = new android.net.Uri.Builder().scheme(com.facebook.common.util.UriUtil.LOCAL_RESOURCE_SCHEME).path(java.lang.String.valueOf(identifier)).build(); } } else if (imagePath.indexOf('~/') === 0) { uri = android.net.Uri.parse(`file:${path.join(knownFolders.currentApp().path, imagePath.replace('~/', ''))}`); } else if (imagePath.indexOf('/') === 0) { uri = android.net.Uri.parse(`file:${imagePath}`); } } else { uri = android.net.Uri.parse(imagePath); } return uri; } export class ImagePipeline { toUri(value) { if (value instanceof android.net.Uri) { return value; } return android.net.Uri.parse(value); } isInDiskCache(uri) { return this._android.isInDiskCacheSync(this.toUri(uri)); } isInBitmapMemoryCache(uri) { return this._android.isInBitmapMemoryCache(this.toUri(uri)); } evictFromMemoryCache(uri) { this._android.evictFromMemoryCache(this.toUri(uri)); } evictFromDiskCache(uri) { this._android.evictFromDiskCache(this.toUri(uri)); } evictFromCache(uri) { this._android.evictFromCache(this.toUri(uri)); } clearCaches() { this._android.clearCaches(); } clearMemoryCaches() { this._android.clearMemoryCaches(); } clearDiskCaches() { this._android.clearDiskCaches(); } prefetchToDiskCache(uri) { return this.prefetchToCache(uri, true); } prefetchToMemoryCache(uri) { return this.prefetchToCache(uri, false); } prefetchToCache(uri, toDiskCache) { return new Promise((resolve, reject) => { try { const nativeUri = android.net.Uri.parse(uri); const request = com.facebook.imagepipeline.request.ImageRequestBuilder.newBuilderWithSource(nativeUri).build(); let datasource; if (toDiskCache) { datasource = this._android.prefetchToDiskCache(request, uri); } else { datasource = this._android.prefetchToBitmapCache(request, uri); } datasource.subscribe(new com.nativescript.image.BaseDataSubscriber(new com.nativescript.image.BaseDataSubscriberListener({ onFailure: reject, onNewResult: resolve, })), com.facebook.common.executors.CallerThreadExecutor.getInstance()); } catch (error) { reject(error); } }); } get android() { return this._android; } set android(value) { this._android = value; } fetchImage() { } } export class ImageError { constructor(throwable) { this._message = throwable.getMessage(); this._errorType = throwable.getClass().getName(); this._stringValue = throwable.toString(); } getMessage() { return this._message; } getErrorType() { return this._errorType; } toString() { return this._stringValue; } } export class ImageInfo { constructor(imageInfo) { this._nativeImageInfo = imageInfo; } getHeight() { return this._nativeImageInfo.getHeight(); } getWidth() { return this._nativeImageInfo.getWidth(); } getQualityInfo() { return this._nativeImageInfo.getQualityInfo(); } } export class FinalEventData extends EventData { get imageInfo() { return this._imageInfo; } set imageInfo(value) { this._imageInfo = value; } get animatable() { return this._animatable; } set animatable(value) { this._animatable = value; } get android() { return this._animatable; } } export class IntermediateEventData extends EventData { get imageInfo() { return this._imageInfo; } set imageInfo(value) { this._imageInfo = value; } } export class FailureEventData extends EventData { get error() { return this._error; } set error(value) { this._error = value; } } export const needRequestImage = function (target, propertyKey, descriptor) { const originalMethod = descriptor.value; descriptor.value = function (...args) { if (!this._canRequestImage) { this._needRequestImage = true; this._needUpdateHierarchy = true; return; } return originalMethod.apply(this, args); }; }; export class Img extends ImageBase { constructor() { super(...arguments); this.isLoading = false; this._canRequestImage = true; this._canUpdateHierarchy = true; this._needUpdateHierarchy = true; this._needRequestImage = false; } onResumeNativeUpdates() { this._canRequestImage = false; this._canUpdateHierarchy = false; super.onResumeNativeUpdates(); this._canUpdateHierarchy = true; this._canRequestImage = true; if (this._needUpdateHierarchy) { this._needUpdateHierarchy = false; this.updateHierarchy(); } if (this._needRequestImage) { this._needRequestImage = false; this.initImage(); } } createNativeView() { if (!initialized) { initialize(initializeConfig); } const view = new com.nativescript.image.DraweeView(this._context); return view; } updateViewSize(imageInfo) { const draweeView = this.nativeViewProtected; if (!draweeView) { return; } if (imageInfo != null) { draweeView.imageWidth = imageInfo.getWidth(); draweeView.imageHeight = imageInfo.getHeight(); } if (!this.aspectRatio && imageInfo != null) { const ratio = imageInfo.getWidth() / imageInfo.getHeight(); draweeView.setAspectRatio(ratio); } else if (this.aspectRatio) { draweeView.setAspectRatio(this.aspectRatio); } else { draweeView.setAspectRatio(0); } } updateImageUri() { const imagePipeLine = getImagePipeline(); const src = this.src; if (!(src instanceof ImageSource)) { const uri = getUri(src); const isInCache = imagePipeLine.isInBitmapMemoryCache(uri); if (isInCache) { imagePipeLine.evictFromCache(uri); } } this.src = null; this.src = src; } [ImageBase.placeholderImageUriProperty.setNative]() { this.updateHierarchy(); } [ImageBase.failureImageUriProperty.setNative]() { this.updateHierarchy(); } [ImageBase.stretchProperty.setNative]() { this.updateHierarchy(); } [ImageBase.fadeDurationProperty.setNative]() { this.updateHierarchy(); } [ImageBase.backgroundUriProperty.setNative]() { this.updateHierarchy(); } [ImageBase.showProgressBarProperty.setNative]() { this.updateHierarchy(); } [ImageBase.progressBarColorProperty.setNative]() { this.updateHierarchy(); } [ImageBase.roundAsCircleProperty.setNative]() { this.updateHierarchy(); } [ImageBase.roundTopLeftRadiusProperty.setNative]() { this.updateHierarchy(); } [ImageBase.roundTopRightRadiusProperty.setNative]() { this.updateHierarchy(); } [ImageBase.roundBottomLeftRadiusProperty.setNative]() { this.updateHierarchy(); } [ImageBase.roundBottomRightRadiusProperty.setNative]() { this.updateHierarchy(); } [ImageBase.tintColorProperty.setNative](value) { this.updateHierarchy(); } [ImageBase.blurRadiusProperty.setNative]() { this.initImage(); } [_a = ImageBase.srcProperty.setNative]() { this.initImage(); } [_b = ImageBase.lowerResSrcProperty.setNative]() { this.initImage(); } [_c = ImageBase.blurDownSamplingProperty.setNative]() { this.initImage(); } [_d = ImageBase.aspectRatioProperty.setNative]() { this.initImage(); } initImage() { if (this.nativeViewProtected) { const src = this.src; if (src) { let drawable; if (src instanceof ImageSource) { drawable = new android.graphics.drawable.BitmapDrawable(ad.getApplicationContext().getResources(), src.android); this.updateViewSize(src.android); } else if (isFontIconURI(src)) { const fontIconCode = src.split('//')[1]; if (fontIconCode !== undefined) { const font = this.style.fontInternal; const color = this.style.color; drawable = new android.graphics.drawable.BitmapDrawable(ad.getApplicationContext().getResources(), ImageSource.fromFontIconCodeSync(fontIconCode, font, color).android); } } if (drawable) { const hierarchy = this.nativeViewProtected.getHierarchy(); hierarchy.setImage(drawable, 1, hierarchy.getFadeDuration() === 0); return; } if (this.noCache) { const uri = getUri(src); const imagePipeLine = getImagePipeline(); const isInCache = imagePipeLine.isInBitmapMemoryCache(uri); if (isInCache) { imagePipeLine.evictFromCache(uri); } } this.isLoading = true; const uri = getUri(src); if (!uri) { console.log(`Error: 'src' not valid: ${src}`); return; } let requestBuilder = com.facebook.imagepipeline.request.ImageRequestBuilder.newBuilderWithSource(uri).setRotationOptions(com.facebook.imagepipeline.common.RotationOptions.autoRotate()); if (this.progressiveRenderingEnabled === true) { requestBuilder = requestBuilder.setProgressiveRenderingEnabled(this.progressiveRenderingEnabled); } if (this.localThumbnailPreviewsEnabled === true) { requestBuilder = requestBuilder.setLocalThumbnailPreviewsEnabled(this.localThumbnailPreviewsEnabled); } if (this.decodeWidth && this.decodeHeight) { requestBuilder = requestBuilder.setResizeOptions(new com.facebook.imagepipeline.common.ResizeOptions(this.decodeWidth, this.decodeHeight)); } if (this.blurRadius) { const postProcessor = new com.nativescript.image.ScalingBlurPostprocessor(2, this.blurRadius, this.blurDownSampling || 1); requestBuilder = requestBuilder.setPostprocessor(postProcessor); } const request = requestBuilder.build(); const that = new WeakRef(this); const listener = new com.facebook.drawee.controller.ControllerListener({ onFinalImageSet(id, imageInfo, animatable) { if (Trace.isEnabled()) { CLog(CLogTypes.info, 'onFinalImageSet', id, imageInfo, animatable); } const nativeView = that && that.get(); if (nativeView) { nativeView.updateViewSize(imageInfo); nativeView.isLoading = false; const info = new ImageInfo(imageInfo); const args = { eventName: ImageBase.finalImageSetEvent, object: nativeView, imageInfo: info, animatable: animatable, }; nativeView.notify(args); } else { console.log("Warning: WeakRef<Image> was GC and no '" + ImageBase.finalImageSetEvent + "' callback will be raised."); } }, onFailure(id, throwable) { if (Trace.isEnabled()) { CLog(CLogTypes.info, 'onFailure', id, throwable); } const nativeView = that && that.get(); if (nativeView) { nativeView.isLoading = false; const imageError = new ImageError(throwable); const args = { eventName: ImageBase.failureEvent, object: nativeView, error: imageError, }; that.get().notify(args); } else { console.log("Warning: WeakRef<Image> was GC and no '" + ImageBase.failureEvent + "' callback will be raised."); } }, onIntermediateImageFailed(id, throwable) { if (Trace.isEnabled()) { CLog(CLogTypes.info, 'onIntermediateImageFailed', id, throwable); } const nativeView = that && that.get(); if (nativeView) { const imageError = new ImageError(throwable); const args = { eventName: ImageBase.intermediateImageFailedEvent, object: nativeView, error: imageError, }; that.get().notify(args); } else { console.log("Warning: WeakRef<Image> was GC and no '" + ImageBase.intermediateImageFailedEvent + "' callback will be raised."); } }, onIntermediateImageSet(id, imageInfo) { if (Trace.isEnabled()) { CLog(CLogTypes.info, 'onIntermediateImageSet', id, imageInfo); } const nativeView = that && that.get(); if (nativeView) { nativeView.updateViewSize(imageInfo); const info = new ImageInfo(imageInfo); const args = { eventName: ImageBase.intermediateImageSetEvent, object: nativeView, imageInfo: info, }; that.get().notify(args); } else { console.log("Warning: WeakRef<Image> was GC and no '" + ImageBase.intermediateImageSetEvent + "' callback will be raised."); } }, onRelease(id) { if (Trace.isEnabled()) { CLog(CLogTypes.info, 'onRelease', id); } const nativeView = that && that.get(); if (nativeView) { const args = { eventName: ImageBase.releaseEvent, object: nativeView, }; that.get().notify(args); } else { console.log("Warning: WeakRef<Image> was GC and no '" + ImageBase.releaseEvent + "' callback will be raised."); } }, onSubmit(id, callerContext) { if (Trace.isEnabled()) { CLog(CLogTypes.info, 'onSubmit', id, callerContext); } const nativeView = that && that.get(); if (nativeView) { const args = { eventName: ImageBase.submitEvent, object: nativeView, }; that.get().notify(args); } else { console.log("Warning: WeakRef<Image> was GC and no 'submitEvent' callback will be raised."); } }, }); const builder = com.facebook.drawee.backends.pipeline.Fresco.newDraweeControllerBuilder(); builder.setImageRequest(request); builder.setCallerContext(src); builder.setControllerListener(listener); builder.setOldController(this.nativeViewProtected.getController()); if (Trace.isEnabled()) { builder.setPerfDataListener(new com.facebook.drawee.backends.pipeline.info.ImagePerfDataListener({ onImageLoadStatusUpdated(param0, param1) { CLog(CLogTypes.info, 'onImageLoadStatusUpdated', param0, param1); }, onImageVisibilityUpdated(param0, param1) { CLog(CLogTypes.info, 'onImageVisibilityUpdated', param0, param1); }, })); } if (this.lowerResSrc) { builder.setLowResImageRequest(com.facebook.imagepipeline.request.ImageRequest.fromUri(getUri(this.lowerResSrc))); } if (this.autoPlayAnimations) { builder.setAutoPlayAnimations(this.autoPlayAnimations); } if (this.tapToRetryEnabled) { builder.setTapToRetryEnabled(this.tapToRetryEnabled); } const controller = builder.build(); this.nativeViewProtected.setController(controller); } else { this.nativeViewProtected.setController(null); this.nativeViewProtected.setImageBitmap(null); } } } updateHierarchy() { if (!this._canUpdateHierarchy) { this._needUpdateHierarchy = true; return; } if (this.nativeViewProtected) { let failureImageDrawable; let placeholderImageDrawable; let backgroundDrawable; if (this.failureImageUri) { failureImageDrawable = this.getDrawable(this.failureImageUri); } if (this.placeholderImageUri) { placeholderImageDrawable = this.getDrawable(this.placeholderImageUri); } if (this.backgroundUri) { backgroundDrawable = this.getDrawable(this.backgroundUri); } const builder = new GenericDraweeHierarchyBuilder(); if (this.failureImageUri && failureImageDrawable) { builder.setFailureImage(failureImageDrawable, this.stretch); } if (this.tintColor) { builder.setActualImageColorFilter(new android.graphics.PorterDuffColorFilter(this.tintColor.android, android.graphics.PorterDuff.Mode.MULTIPLY)); } if (this.placeholderImageUri && placeholderImageDrawable) { builder.setPlaceholderImage(placeholderImageDrawable, this.stretch); } if (this.stretch) { builder.setActualImageScaleType(this.stretch); } if (this.fadeDuration) { builder.setFadeDuration(this.fadeDuration); } else { builder.setFadeDuration(0); } if (this.backgroundUri && backgroundDrawable) { builder.setBackground(backgroundDrawable); } if (this.showProgressBar) { builder.setProgressBarImage(this.progressBarColor, this.stretch); } if (this.roundAsCircle) { builder.setRoundingParamsAsCircle(); } if (this.roundBottomLeftRadius || this.roundBottomRightRadius || this.roundTopLeftRadius || this.roundTopRightRadius) { const topLeftRadius = this.roundTopLeftRadius || 0; const topRightRadius = this.roundTopRightRadius || 0; const bottomRightRadius = this.roundBottomRightRadius || 0; const bottomLeftRadius = this.roundBottomLeftRadius || 0; builder.setCornersRadii(topLeftRadius, topRightRadius, bottomRightRadius, bottomLeftRadius); } const hierarchy = builder.build(); this.nativeViewProtected.setHierarchy(hierarchy); } } getDrawable(path) { let drawable; if (typeof path === 'string') { if (isFontIconURI(path)) { const fontIconCode = (path).split('//')[1]; if (fontIconCode !== undefined) { const font = this.style.fontInternal; const color = this.style.color; drawable = new android.graphics.drawable.BitmapDrawable(ad.getApplicationContext().getResources(), ImageSource.fromFontIconCodeSync(fontIconCode, font, color).android); } } else if (isFileOrResourcePath(path)) { if (path.indexOf(RESOURCE_PREFIX) === 0) { return this.getDrawableFromResource(path); } else { drawable = this.getDrawableFromLocalFile(path); } } } else { drawable = new android.graphics.drawable.BitmapDrawable(ad.getApplicationContext().getResources(), path.android); } return drawable; } getDrawableFromLocalFile(localFilePath) { const img = ImageSource.fromFileSync(localFilePath); let drawable = null; if (img) { drawable = new android.graphics.drawable.BitmapDrawable(ad.getApplicationContext().getResources(), img.android); } return drawable; } getDrawableFromResource(resourceName) { const identifier = ad.getApplication().getResources().getIdentifier(resourceName.substr(RESOURCE_PREFIX.length), 'drawable', ad.getApplication().getPackageName()); return identifier; } startAnimating() { if (this.nativeViewProtected) { const controller = this.nativeViewProtected.getController(); if (controller) { const animatable = controller.getAnimatable(); if (animatable) { animatable.start(); } } } } stopAnimating() { if (this.nativeViewProtected) { const controller = this.nativeViewProtected.getController(); if (controller) { const animatable = controller.getAnimatable(); if (animatable) { animatable.stop(); } } } } } __decorate([ needRequestImage ], Img.prototype, _a, null); __decorate([ needRequestImage ], Img.prototype, _b, null); __decorate([ needRequestImage ], Img.prototype, _c, null); __decorate([ needRequestImage ], Img.prototype, _d, null); class GenericDraweeHierarchyBuilder { constructor() { const res = androidApp.context.getResources(); this.nativeBuilder = new com.facebook.drawee.generic.GenericDraweeHierarchyBuilder(res); } setPlaceholderImage(drawable, scaleType) { if (!this.nativeBuilder) { return this; } if (scaleType) { this.nativeBuilder.setPlaceholderImage(drawable, getScaleType(scaleType)); } else { this.nativeBuilder.setPlaceholderImage(drawable); } return this; } setActualImageColorFilter(filter) { if (!this.nativeBuilder) { return this; } this.nativeBuilder.setActualImageColorFilter(filter); return this; } setFailureImage(drawable, scaleType) { if (!this.nativeBuilder) { return null; } if (scaleType) { this.nativeBuilder.setFailureImage(drawable, getScaleType(scaleType)); } else { this.nativeBuilder.setFailureImage(drawable); } return this; } setActualImageScaleType(scaleType) { if (!this.nativeBuilder) { return this; } this.nativeBuilder.setActualImageScaleType(getScaleType(scaleType)); return this; } build() { if (!this.nativeBuilder) { return null; } return this.nativeBuilder.build(); } setFadeDuration(duration) { if (!this.nativeBuilder) { return null; } this.nativeBuilder.setFadeDuration(duration); return this; } setBackground(drawable) { if (!this.nativeBuilder) { return this; } this.nativeBuilder.setBackground(drawable); return this; } setProgressBarImage(color, stretch) { if (!this.nativeBuilder) { return null; } const drawable = new com.facebook.drawee.drawable.ProgressBarDrawable(); if (color) { drawable.setColor(android.graphics.Color.parseColor(color)); } this.nativeBuilder.setProgressBarImage(drawable, getScaleType(stretch)); return this; } setRoundingParamsAsCircle() { if (!this.nativeBuilder) { return this; } const params = com.facebook.drawee.generic.RoundingParams.asCircle(); this.nativeBuilder.setRoundingParams(params); return this; } setCornersRadii(topLeft, topRight, bottomRight, bottomLeft) { if (!this.nativeBuilder) { return this; } const params = new com.facebook.drawee.generic.RoundingParams(); params.setCornersRadii(topLeft, topRight, bottomRight, bottomLeft); this.nativeBuilder.setRoundingParams(params); return this; } } function getScaleType(scaleType) { if (isString(scaleType)) { switch (scaleType) { case ScaleType.Center: return com.facebook.drawee.drawable.ScalingUtils.ScaleType.CENTER; case ScaleType.AspectFill: case ScaleType.CenterCrop: return com.facebook.drawee.drawable.ScalingUtils.ScaleType.CENTER_CROP; case ScaleType.CenterInside: return com.facebook.drawee.drawable.ScalingUtils.ScaleType.CENTER_INSIDE; case ScaleType.FitCenter: case ScaleType.AspectFit: return com.facebook.drawee.drawable.ScalingUtils.ScaleType.FIT_CENTER; case ScaleType.FitEnd: return com.facebook.drawee.drawable.ScalingUtils.ScaleType.FIT_END; case ScaleType.FitStart: return com.facebook.drawee.drawable.ScalingUtils.ScaleType.FIT_START; case ScaleType.Fill: case ScaleType.FitXY: return com.facebook.drawee.drawable.ScalingUtils.ScaleType.FIT_XY; case ScaleType.FocusCrop: return com.facebook.drawee.drawable.ScalingUtils.ScaleType.FOCUS_CROP; default: break; } } return null; } //# sourceMappingURL=image.android.js.map