Skip to content

Commit

Permalink
fix(android): src is now loaded sync. You can change the behavior wit…
Browse files Browse the repository at this point in the history
…h the new `async` property
  • Loading branch information
farfromrefug committed Nov 19, 2023
1 parent 927a64f commit 7b28195
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 47 deletions.
7 changes: 6 additions & 1 deletion plugin/platforms/android/native-api-usage.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@
"com.airbnb.lottie.model:KeyPath",
"com.airbnb.lottie.value:LottieValueCallback",
"com.airbnb.lottie:LottieProperty",
"com.airbnb.lottie:SimpleColorFilter",
"com.airbnb.lottie:RenderMode",
"android.animation:Animator",
"android.animation:Animator.AnimatorListener"
"android.animation:Animator.AnimatorListener",
"com.airbnb.lottie:LottieResult",
"com.airbnb.lottie:LottieOnCompositionLoadedListener",
"com.airbnb.lottie:LottieComposition",
"com.airbnb.lottie:LottieCompositionFactory"
]
}
143 changes: 97 additions & 46 deletions src/lottie.android.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,26 @@ import { clamp } from './utils';
let LottieProperty: typeof com.airbnb.lottie.LottieProperty;
let LottieKeyPath: typeof com.airbnb.lottie.model.KeyPath;
let LottieValueCallback: typeof com.airbnb.lottie.value.LottieValueCallback;
let LottieCompositionFactory: typeof com.airbnb.lottie.LottieCompositionFactory;

const cache = new Map();
function loadLottieJSON(iconSrc) {
async function loadLottieJSON(iconSrc) {
if (!cache.has(iconSrc)) {
const file = File.fromPath(iconSrc);
return file.readText().then((r) => {
cache.set(iconSrc, r);
return r;
});
const r = await file.readText();
cache.set(iconSrc, r);
return r;
}
return Promise.resolve(cache.get(iconSrc));
return cache.get(iconSrc);
}
function loadLottieJSONSync(iconSrc) {
if (!cache.has(iconSrc)) {
const file = File.fromPath(iconSrc);
const r = file.readTextSync();
cache.set(iconSrc, r);
return r;
}
return cache.get(iconSrc);
}

export const RenderMode = {
Expand All @@ -52,7 +61,8 @@ export class LottieView extends LottieViewBase {
return new com.nativescript.lottie.LottieAnimationView(this._context);
}

animatorListener;
animatorListener: android.animation.Animator.AnimatorListener;
loadedListener: com.airbnb.lottie.LottieOnCompositionLoadedListener;
_completionBlock;
//@ts-ignore
get completionBlock() {
Expand Down Expand Up @@ -95,58 +105,104 @@ export class LottieView extends LottieViewBase {
if (this.animatorListener) {
this.nativeViewProtected.addAnimatorListener(this.animatorListener);
}
// if (this.src) {
// this[srcProperty.setNative](this.src);
// }

// if (this.loop) {
// this.nativeView.loop(this.loop);
// }
if (!this.loadedListener) {
this.loadedListener = new com.airbnb.lottie.LottieOnCompositionLoadedListener({
onCompositionLoaded: (composition) => {
this.notify({ eventName: 'compositionLoaded', composition });
}
});
}
this.nativeViewProtected.addLottieOnCompositionLoadedListener(this.loadedListener);

// if (this.autoPlay) {
// this.playAnimation();
// }
}

public disposeNativeView(): void {
if (this.animatorListener) {
this.nativeViewProtected.removeAnimatorListener(this.animatorListener);
}
if (this.loadedListener) {
this.nativeViewProtected.removeLottieOnCompositionLoadedListener(this.loadedListener);
}
super.disposeNativeView();
}

[srcProperty.setNative](src: string) {
const view = this.nativeViewProtected;
if (!src) {
// lottie does not support "clearing the animation"
// view.setAnimation(null);
} else if (src[0] === '{') {
view.setAnimationFromJson(src, null);
} else if (src.startsWith(Utils.RESOURCE_PREFIX)) {
const resName = src.replace(Utils.RESOURCE_PREFIX, '');
view.setAnimation(resName);
} else {
if (!/.(json|zip|lottie)$/.test(src)) {
src += '.json';
try {
if (LottieCompositionFactory) {
LottieCompositionFactory = com.airbnb.lottie.LottieCompositionFactory;
}
if (src[0] === '~') {
this.nativeView.setAnimation('app/' + src.substring(2));
} else if (!src.startsWith('file:/') && src[0] !== '/') {
this.nativeView.setAnimation(src);
const view = this.nativeViewProtected;
let result: com.airbnb.lottie.LottieResult<com.airbnb.lottie.LottieComposition>;
if (!src) {
// lottie does not support "clearing the animation"
// view.setAnimation(null);
} else if (src[0] === '{') {
if (this.async) {
view.setAnimationFromJson(src, null);
} else {
result = LottieCompositionFactory.fromJsonStringSync(this._context, src);
}
} else if (src.startsWith(Utils.RESOURCE_PREFIX)) {
const resName = src.replace(Utils.RESOURCE_PREFIX, '');
if (this.async) {
view.setAnimation(resName);
} else {
result = com.airbnb.lottie.LottieCompositionFactory.fromAssetSync(this._context, resName);
}
} else {
loadLottieJSON(src).then((r) => {
this.nativeView.setAnimationFromJson(r, null);
});
if (!/.(json|zip|lottie)$/.test(src)) {
src += '.json';
}
if (src[0] === '~') {
if (this.async) {
view.setAnimation('app/' + src.substring(2));
} else {
result = com.airbnb.lottie.LottieCompositionFactory.fromAssetSync(
this._context,
'app/' + src.substring(2)
);
}
} else if (!src.startsWith('file:/') && src[0] !== '/') {
if (this.async) {
view.setAnimation('app/' + src);
} else {
result = com.airbnb.lottie.LottieCompositionFactory.fromAssetSync(this._context, src);
}
} else {
if (this.async) {
loadLottieJSON(src).then((result) => {
if (this.nativeViewProtected) {
this.nativeViewProtected.setAnimationFromJson(result, null);
}
});
} else {
result = LottieCompositionFactory.fromJsonStringSync(this._context, loadLottieJSONSync(src));
}
}
}
}

if (this.autoPlay) {
this.playAnimation();
if (result) {
if (result.getException()) {
console.error(result.getException());
// view.setComposition(null);
} else {
view.setComposition(result.getValue());
//in sync loading we need to fire it ourselves
// if we dont differ it from now it wont be received
setTimeout(() => {
this.notify({ eventName: 'compositionLoaded', composition: result.getValue() });
}, 0);
}
}
if (this.autoPlay) {
this.playAnimation();
}
} catch (error) {
console.error(error);
}
}

[loopProperty.setNative](loop: boolean) {
this.nativeViewProtected.loop(loop);
this.nativeViewProtected.setRepeatCount(loop ? -1 /* android.animation.ValueAnimator.INFINITE */ : 0);
}
[renderModeProperty.setNative](renderMode) {
this.nativeViewProtected.setRenderMode(renderMode);
Expand Down Expand Up @@ -205,11 +261,6 @@ export class LottieView extends LottieViewBase {
// LottieProperty.COLOR,
// new LottieValueCallback(java.lang.Integer.valueOf(value.android))
// );
nativeView.addValueCallback(
new LottieKeyPath(nativeKeyPath as any),
LottieProperty.COLOR,
new LottieValueCallback(java.lang.Integer.valueOf(value.android))
);
}
}

Expand Down
7 changes: 7 additions & 0 deletions src/lottie.common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { CoreTypes, Property, View, booleanConverter } from '@nativescript/core'

export class LottieViewBase extends View {
public stretch: CoreTypes.ImageStretchType;
public async: boolean;
public src: string;
public loop: boolean;
public autoPlay: boolean;
Expand All @@ -21,6 +22,12 @@ export const srcProperty = new Property<LottieViewBase, string>({
});
srcProperty.register(LottieViewBase);

export const asyncProperty = new Property<LottieViewBase, boolean>({
name: 'async',
defaultValue: false,
valueConverter: booleanConverter
});
asyncProperty.register(LottieViewBase);
export const loopProperty = new Property<LottieViewBase, boolean>({
name: 'loop',
defaultValue: false,
Expand Down

0 comments on commit 7b28195

Please sign in to comment.