@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
JavaScript
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