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.

344 lines 14.5 kB
import { Color, Length, Property, Trace, View, booleanConverter } from '@nativescript/core'; import { isAndroid } from '@nativescript/core/platform'; export function colorConverter(v) { if (!v || v instanceof Color) { return v; } return new Color(v); } function isNonNegativeFiniteNumber(value) { return isFinite(value) && !isNaN(value) && value >= 0; } function parseThickness(value) { if (typeof value === 'string') { const arr = value.split(/[ ,]+/); let top; let right; let bottom; let left; if (arr.length === 1) { top = arr[0]; right = arr[0]; bottom = arr[0]; left = arr[0]; } else if (arr.length === 2) { top = arr[0]; bottom = arr[0]; right = arr[1]; left = arr[1]; } else if (arr.length === 3) { top = arr[0]; right = arr[1]; left = arr[1]; bottom = arr[2]; } else if (arr.length === 4) { top = arr[0]; right = arr[1]; bottom = arr[2]; left = arr[3]; } else { throw new Error('Expected 1, 2, 3 or 4 parameters. Actual: ' + value); } return { top, right, bottom, left }; } else { return value; } } export var CLogTypes; (function (CLogTypes) { CLogTypes[CLogTypes["log"] = 0] = "log"; CLogTypes[CLogTypes["info"] = 1] = "info"; CLogTypes[CLogTypes["warning"] = 2] = "warning"; CLogTypes[CLogTypes["error"] = 3] = "error"; })(CLogTypes || (CLogTypes = {})); export const ImageViewTraceCategory = 'NativescriptImage'; export const CLog = (type, ...args) => { Trace.write(args.map((a) => (a && typeof a === 'object' ? JSON.stringify(a) : a)).join(' '), ImageViewTraceCategory, type); }; export var ScaleType; (function (ScaleType) { ScaleType["None"] = "none"; ScaleType["Fill"] = "fill"; ScaleType["AspectFill"] = "aspectFill"; ScaleType["AspectFit"] = "aspectFit"; ScaleType["Center"] = "center"; ScaleType["CenterCrop"] = "centerCrop"; ScaleType["CenterInside"] = "centerInside"; ScaleType["FitCenter"] = "fitCenter"; ScaleType["FitEnd"] = "fitEnd"; ScaleType["FitStart"] = "fitStart"; ScaleType["FitXY"] = "fitXY"; ScaleType["FocusCrop"] = "focusCrop"; })(ScaleType || (ScaleType = {})); export function wrapNativeException(ex, errorType = typeof ex) { if (typeof ex === 'string') { return new Error(ex); } if (!(ex instanceof Error)) { if (__ANDROID__) { const err = new Error(ex.toString()); err['nativeException'] = ex; //@ts-ignore err['stackTrace'] = com.tns.NativeScriptException.getStackTraceAsString(ex); return err; } if (__IOS__) { const err = new Error(ex.localizedDescription); err['nativeException'] = ex; err['code'] = ex.code; err['domain'] = ex.domain; // TODO: we loose native stack. see how to get it return err; } } return ex; } export class EventData { get eventName() { return this._eventName; } set eventName(value) { this._eventName = value; } get object() { return this._object; } set object(value) { this._object = value; } } export const srcProperty = new Property({ name: 'src' }); export const headersProperty = new Property({ name: 'headers' }); export const lowerResSrcProperty = new Property({ name: 'lowerResSrc' }); export const placeholderImageUriProperty = new Property({ name: 'placeholderImageUri' }); export const failureImageUriProperty = new Property({ name: 'failureImageUri' }); export const stretchProperty = new Property({ name: 'stretch' }); export const backgroundUriProperty = new Property({ name: 'backgroundUri' }); export const progressiveRenderingEnabledProperty = new Property({ name: 'progressiveRenderingEnabled', valueConverter: booleanConverter }); export const localThumbnailPreviewsEnabledProperty = new Property({ name: 'localThumbnailPreviewsEnabled', valueConverter: booleanConverter }); export const showProgressBarProperty = new Property({ name: 'showProgressBar', valueConverter: booleanConverter, defaultValue: false }); export const progressBarColorProperty = new Property({ name: 'progressBarColor', valueConverter: colorConverter }); export const roundAsCircleProperty = new Property({ name: 'roundAsCircle', valueConverter: booleanConverter, affectsLayout: isAndroid }); export const blurRadiusProperty = new Property({ name: 'blurRadius', valueConverter: (v) => parseFloat(v) }); export const blurDownSamplingProperty = new Property({ name: 'blurDownSampling', valueConverter: (v) => parseFloat(v) }); export const imageRotationProperty = new Property({ name: 'imageRotation', valueConverter: (v) => parseFloat(v), defaultValue: 0 }); export const autoPlayAnimationsProperty = new Property({ name: 'autoPlayAnimations', valueConverter: booleanConverter }); export const tapToRetryEnabledProperty = new Property({ name: 'tapToRetryEnabled', valueConverter: booleanConverter }); export const aspectRatioProperty = new Property({ name: 'aspectRatio', affectsLayout: true, valueConverter: (v) => parseFloat(v) }); export const decodeWidthProperty = new Property({ name: 'decodeWidth', valueConverter: (v) => parseFloat(v) }); export const decodeHeightProperty = new Property({ name: 'decodeHeight', valueConverter: (v) => parseFloat(v) }); export const tintColorProperty = new Property({ name: 'tintColor' }); export const alwaysFadeProperty = new Property({ name: 'alwaysFade', valueConverter: booleanConverter, defaultValue: false }); export const fadeDurationProperty = new Property({ name: 'fadeDuration', valueConverter: (v) => parseFloat(v) }); export const noCacheProperty = new Property({ name: 'noCache', defaultValue: false, valueConverter: booleanConverter }); export const roundTopLeftRadiusProperty = new Property({ name: 'roundTopLeftRadius', defaultValue: 0, valueConverter: (v) => Length.toDevicePixels(Length.parse(v)) }); export const roundTopRightRadiusProperty = new Property({ name: 'roundTopRightRadius', defaultValue: 0, valueConverter: (v) => Length.toDevicePixels(Length.parse(v)) }); export const roundBottomLeftRadiusProperty = new Property({ name: 'roundBottomLeftRadius', defaultValue: 0, valueConverter: (v) => Length.toDevicePixels(Length.parse(v)) }); export const roundBottomRightRadiusProperty = new Property({ name: 'roundBottomRightRadius', defaultValue: 0, valueConverter: (v) => Length.toDevicePixels(Length.parse(v)) }); // export const roundRadiusProperty = new ShorthandProperty<any, string | CoreTypes.LengthType>({ // name: 'borderRadius', // cssName: 'border-radius', // getter(this) { // if ( // Length.equals(this.borderTopLeftRadius, this.borderTopRightRadius) && // Length.equals(this.borderTopLeftRadius, this.borderBottomRightRadius) && // Length.equals(this.borderTopLeftRadius, this.borderBottomLeftRadius) // ) { // return this.borderTopLeftRadius; // } // return `${Length.convertToString(this.borderTopLeftRadius)} ${Length.convertToString(this.borderTopRightRadius)} ${Length.convertToString( // this.borderBottomRightRadius // )} ${Length.convertToString(this.borderBottomLeftRadius)}`; // }, // //@ts-ignore // converter(value) { // if (typeof value === 'string') { // const borderRadius = parseThickness(value); // return [ // [roundTopLeftRadiusProperty, borderRadius.top], // [roundTopRightRadiusProperty, borderRadius.right], // [roundBottomRightRadiusProperty, borderRadius.bottom], // [roundBottomLeftRadiusProperty, borderRadius.left] // ]; // } else { // return [ // [roundTopLeftRadiusProperty, value], // [roundTopRightRadiusProperty, value], // [roundBottomRightRadiusProperty, value], // [roundBottomLeftRadiusProperty, value] // ]; // } // } // }); export const loadModeProperty = new Property({ name: 'loadMode', defaultValue: 'sync' }); export const clipToBoundsProperty = new Property({ name: 'clipToBounds', defaultValue: true, valueConverter: booleanConverter }); export const animatedImageViewProperty = new Property({ name: 'animatedImageView', defaultValue: false, valueConverter: booleanConverter }); export const needRequestImage = function (target, propertyKey, descriptor) { const originalMethod = descriptor.value; descriptor.value = function (...args) { if (!this.mCanRequestImage) { this.mNeedRequestImage = true; return; } return originalMethod.apply(this, args); }; }; export class ImageBase extends View { constructor() { super(...arguments); this.mCanRequestImage = true; this.mNeedRequestImage = false; } // public static blendingModeProperty = new Property<ImageBase, string>({ name: 'blendingMode' }); get nativeImageViewProtected() { return this.nativeViewProtected; } onResumeNativeUpdates() { // {N} suspends properties update on `_suspendNativeUpdates`. So we only need to do this in onResumeNativeUpdates this.mCanRequestImage = false; super.onResumeNativeUpdates(); this.mCanRequestImage = true; if (this.mNeedRequestImage) { this.mNeedRequestImage = false; this.initImage(); } } handleImageProgress(value, totalSize) { } static needsSizeAdjustment(scaleType) { if (scaleType === undefined) { return true; } switch (scaleType) { case ScaleType.FocusCrop: case ScaleType.Center: case ScaleType.CenterCrop: case ScaleType.CenterInside: case ScaleType.FitCenter: case ScaleType.AspectFit: case ScaleType.FitXY: return true; default: return false; } } computeScaleFactor(measureWidth, measureHeight, widthIsFinite, heightIsFinite, nativeWidth, nativeHeight, aspectRatio) { let scaleW = 1; let scaleH = 1; if (ImageBase.needsSizeAdjustment(this.stretch) || widthIsFinite || heightIsFinite) { const nativeScale = nativeWidth > 0 && nativeHeight > 0 ? nativeWidth / nativeHeight : 1; const measureScale = measureWidth > 0 && measureHeight > 0 ? measureWidth / measureHeight : 1; scaleW = nativeWidth > 0 ? measureWidth / nativeWidth : 1; scaleH = nativeHeight > 0 ? measureHeight / nativeHeight : 1; if (Trace.isEnabled()) { CLog(CLogTypes.info, 'computeScaleFactor', measureWidth, measureHeight, nativeWidth, nativeHeight, widthIsFinite, heightIsFinite, aspectRatio, nativeScale, measureScale); } if (aspectRatio > 0) { if (!widthIsFinite) { scaleH = 1; scaleW = aspectRatio; } else if (!heightIsFinite) { scaleW = 1; scaleH = 1 / aspectRatio; } } else { if (!widthIsFinite) { scaleH = 1; scaleW = nativeScale * scaleH; } else if (!heightIsFinite) { scaleW = 1; scaleH = measureScale / nativeScale; } else { // No infinite dimensions. switch (this.stretch) { case ScaleType.FitXY: case ScaleType.FocusCrop: case ScaleType.Fill: break; default: if (measureScale > nativeScale) { scaleH = 1; scaleW = nativeScale * scaleH; } else { scaleW = 1; scaleH = measureScale / nativeScale; } } } } } return { width: scaleW, height: scaleH }; } } ImageBase.finalImageSetEvent = 'finalImageSet'; ImageBase.failureEvent = 'failure'; ImageBase.intermediateImageFailedEvent = 'intermediateImageFailed'; ImageBase.intermediateImageSetEvent = 'intermediateImageSet'; ImageBase.releaseEvent = 'release'; ImageBase.submitEvent = 'submit'; srcProperty.register(ImageBase); headersProperty.register(ImageBase); lowerResSrcProperty.register(ImageBase); placeholderImageUriProperty.register(ImageBase); failureImageUriProperty.register(ImageBase); stretchProperty.register(ImageBase); fadeDurationProperty.register(ImageBase); backgroundUriProperty.register(ImageBase); progressiveRenderingEnabledProperty.register(ImageBase); localThumbnailPreviewsEnabledProperty.register(ImageBase); showProgressBarProperty.register(ImageBase); progressBarColorProperty.register(ImageBase); roundAsCircleProperty.register(ImageBase); roundTopLeftRadiusProperty.register(ImageBase); roundTopRightRadiusProperty.register(ImageBase); roundBottomLeftRadiusProperty.register(ImageBase); roundBottomRightRadiusProperty.register(ImageBase); blurRadiusProperty.register(ImageBase); blurDownSamplingProperty.register(ImageBase); imageRotationProperty.register(ImageBase); autoPlayAnimationsProperty.register(ImageBase); tapToRetryEnabledProperty.register(ImageBase); aspectRatioProperty.register(ImageBase); decodeWidthProperty.register(ImageBase); decodeHeightProperty.register(ImageBase); alwaysFadeProperty.register(ImageBase); noCacheProperty.register(ImageBase); clipToBoundsProperty.register(ImageBase); animatedImageViewProperty.register(ImageBase); loadModeProperty.register(ImageBase); // roundRadiusProperty.register(ImageBase as any); // ImageBase.blendingModeProperty.register(ImageBase); //# sourceMappingURL=index-common.js.map