@octane-xplat/lottie 0.0.1 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -2
- package/dist/native/cx.mobile.js +11 -0
- package/dist/native/escape-props.js +39 -0
- package/dist/native/index.js +182 -0
- package/dist/native/layout-child.js +38 -0
- package/dist/native/octane-client-build.json +8 -0
- package/dist/native/vendor/ui-lottie/index.android.js +286 -0
- package/dist/native/vendor/ui-lottie/index.ios.js +214 -0
- package/dist/native/vendor/ui-lottie/src/lottie/index.common.js +50 -0
- package/dist/native/vendor/ui-lottie/src/lottie/utils.js +6 -0
- package/dist/web/escape-props.web.js +17 -0
- package/dist/web/index.js +332 -0
- package/dist/web/layout-child.web.js +47 -0
- package/dist/web/octane-client-build.json +8 -0
- package/package.json +81 -10
- package/platforms/android/include.gradle +7 -0
- package/platforms/android/java/com/nativescript/lottie/LottieAnimationView.java +92 -0
- package/platforms/android/lottie.aar +0 -0
- package/platforms/android/native-api-usage.json +16 -0
- package/platforms/ios/Podfile +5 -0
- package/src/Lottie.tsrx +161 -0
- package/src/Lottie.web.tsrx +135 -0
- package/src/cx.mobile.ts +8 -0
- package/src/escape-props.ts +65 -0
- package/src/escape-props.web.ts +25 -0
- package/src/index.ts +2 -0
- package/src/index.web.ts +2 -0
- package/src/layout-child.ts +57 -0
- package/src/layout-child.web.ts +108 -0
- package/src/native-elements.d.ts +8 -0
- package/src/props.ts +128 -0
- package/src/references.d.ts +3 -0
- package/src/vendor/ui-lottie/LICENSE.md +21 -0
- package/src/vendor/ui-lottie/src/lottie/index.android.ts +447 -0
- package/src/vendor/ui-lottie/src/lottie/index.common.ts +84 -0
- package/src/vendor/ui-lottie/src/lottie/index.d.ts +133 -0
- package/src/vendor/ui-lottie/src/lottie/index.ios.ts +345 -0
- package/src/vendor/ui-lottie/src/lottie/typings/android.d.ts +4149 -0
- package/src/vendor/ui-lottie/src/lottie/typings/android.nativescript.d.ts +12 -0
- package/src/vendor/ui-lottie/src/lottie/typings/dotlottie.ios.d.ts +14 -0
- package/src/vendor/ui-lottie/src/lottie/typings/ios.d.ts +384 -0
- package/src/vendor/ui-lottie/src/lottie/utils.ts +9 -0
- package/types/generated/.tsrx-typegen-manifest.json +18 -0
- package/types/generated/Lottie.d.ts +7 -0
- package/types/generated/Lottie.web.d.ts +7 -0
- package/types/generated/cx.mobile.d.ts +6 -0
- package/types/generated/escape-props.d.ts +15 -0
- package/types/generated/escape-props.web.d.ts +5 -0
- package/types/generated/index.d.ts +2 -0
- package/types/generated/index.web.d.ts +2 -0
- package/types/generated/layout-child.d.ts +6 -0
- package/types/generated/layout-child.web.d.ts +15 -0
- package/types/generated/props.d.ts +106 -0
- package/types/generated/vendor/ui-lottie/src/lottie/index.common.d.ts +30 -0
- package/types/generated/vendor/ui-lottie/src/lottie/index.ios.d.ts +35 -0
- package/types/generated/vendor/ui-lottie/src/lottie/utils.d.ts +1 -0
- package/index.d.ts +0 -1
- package/index.js +0 -2
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
/**********************************************************************************
|
|
2
|
+
* (c) 2017, Brad Martin.
|
|
3
|
+
* Licensed under the MIT license.
|
|
4
|
+
*
|
|
5
|
+
* Version 1.0.0 bradwaynemartin@gmail.com
|
|
6
|
+
**********************************************************************************/
|
|
7
|
+
|
|
8
|
+
// Vendored from @nativescript-community/ui-lottie (MIT), fork branch
|
|
9
|
+
// xplat-fixes on octane-xplat/ui-lottie — device-probed fixes for dead
|
|
10
|
+
// sync-src, missing events/pause-resume, URL/.lottie sources, async
|
|
11
|
+
// autoPlay, completion dedupe, opacity scale, Podfile pin.
|
|
12
|
+
// @ts-nocheck — vendored upstream code, not strict-clean; kept
|
|
13
|
+
// diff-identical to the fork so fix branches stay PR-able.
|
|
14
|
+
/// <reference path="./typings/android.d.ts" />
|
|
15
|
+
import { Color, File, Http, Utils, knownFolders, path } from '@nativescript/core';
|
|
16
|
+
import { LottieViewBase, autoPlayProperty, keyPathColorsProperty, loopProperty, progressProperty, renderModeProperty, srcProperty, stretchProperty } from './index.common';
|
|
17
|
+
import { clamp } from './utils';
|
|
18
|
+
|
|
19
|
+
let LottieProperty: typeof com.airbnb.lottie.LottieProperty;
|
|
20
|
+
let LottieKeyPath: typeof com.airbnb.lottie.model.KeyPath;
|
|
21
|
+
let LottieValueCallback: typeof com.airbnb.lottie.value.LottieValueCallback;
|
|
22
|
+
let LottieCompositionFactory: typeof com.airbnb.lottie.LottieCompositionFactory;
|
|
23
|
+
|
|
24
|
+
const cache = new Map();
|
|
25
|
+
async function loadLottieJSON(iconSrc) {
|
|
26
|
+
if (!cache.has(iconSrc)) {
|
|
27
|
+
const file = File.fromPath(iconSrc);
|
|
28
|
+
const r = await file.readText();
|
|
29
|
+
cache.set(iconSrc, r);
|
|
30
|
+
return r;
|
|
31
|
+
}
|
|
32
|
+
return cache.get(iconSrc);
|
|
33
|
+
}
|
|
34
|
+
function loadLottieJSONSync(iconSrc) {
|
|
35
|
+
if (!cache.has(iconSrc)) {
|
|
36
|
+
const file = File.fromPath(iconSrc);
|
|
37
|
+
const r = file.readTextSync();
|
|
38
|
+
cache.set(iconSrc, r);
|
|
39
|
+
return r;
|
|
40
|
+
}
|
|
41
|
+
return cache.get(iconSrc);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const RenderMode = {
|
|
45
|
+
get AUTOMATIC() {
|
|
46
|
+
return com.airbnb.lottie.RenderMode.AUTOMATIC;
|
|
47
|
+
},
|
|
48
|
+
get HARDWARE() {
|
|
49
|
+
return com.airbnb.lottie.RenderMode.HARDWARE;
|
|
50
|
+
},
|
|
51
|
+
get SOFTWARE() {
|
|
52
|
+
return com.airbnb.lottie.RenderMode.SOFTWARE;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export class LottieView extends LottieViewBase {
|
|
57
|
+
nativeViewProtected: com.airbnb.lottie.LottieAnimationView;
|
|
58
|
+
|
|
59
|
+
public createNativeView() {
|
|
60
|
+
return new com.nativescript.lottie.LottieAnimationView(this._context);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
animatorListener: android.animation.Animator.AnimatorListener;
|
|
64
|
+
loadedListener: com.airbnb.lottie.LottieOnCompositionLoadedListener;
|
|
65
|
+
_completionBlock;
|
|
66
|
+
_cancelled = false;
|
|
67
|
+
//@ts-ignore
|
|
68
|
+
get completionBlock() {
|
|
69
|
+
return this._completionBlock;
|
|
70
|
+
}
|
|
71
|
+
set completionBlock(block) {
|
|
72
|
+
this._completionBlock = block;
|
|
73
|
+
if (block) {
|
|
74
|
+
if (!this.animatorListener) {
|
|
75
|
+
const that = new WeakRef(this);
|
|
76
|
+
this.animatorListener = new android.animation.Animator.AnimatorListener({
|
|
77
|
+
onAnimationCancel: (_animator) => {
|
|
78
|
+
// ValueAnimator.cancel() fires onAnimationCancel AND then
|
|
79
|
+
// onAnimationEnd — report once, in onAnimationEnd, with the
|
|
80
|
+
// correct finished flag (matching iOS, where pause()/stop()
|
|
81
|
+
// invoke the completion block a single time with false).
|
|
82
|
+
const owner = that?.get();
|
|
83
|
+
if (owner) {
|
|
84
|
+
owner._cancelled = true;
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
onAnimationEnd: (_animator) => {
|
|
88
|
+
const owner = that?.get();
|
|
89
|
+
if (owner?._completionBlock) {
|
|
90
|
+
owner._completionBlock(!owner._cancelled);
|
|
91
|
+
}
|
|
92
|
+
if (owner) {
|
|
93
|
+
owner._cancelled = false;
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
onAnimationRepeat: (_animator) => {
|
|
97
|
+
// noop
|
|
98
|
+
},
|
|
99
|
+
onAnimationStart: (_animator) => {
|
|
100
|
+
// noop
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
if (this.nativeViewProtected) {
|
|
104
|
+
this.nativeViewProtected.addAnimatorListener(this.animatorListener);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
} else if (this.animatorListener) {
|
|
108
|
+
if (this.nativeViewProtected) {
|
|
109
|
+
this.nativeViewProtected.removeAnimatorListener(this.animatorListener);
|
|
110
|
+
}
|
|
111
|
+
this.animatorListener = null;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
public initNativeView(): void {
|
|
115
|
+
if (this.animatorListener) {
|
|
116
|
+
this.nativeViewProtected.addAnimatorListener(this.animatorListener);
|
|
117
|
+
}
|
|
118
|
+
if (!this.loadedListener) {
|
|
119
|
+
const that = new WeakRef(this);
|
|
120
|
+
this.loadedListener = new com.airbnb.lottie.LottieOnCompositionLoadedListener({
|
|
121
|
+
onCompositionLoaded: (composition) => {
|
|
122
|
+
const owner = that?.get();
|
|
123
|
+
if (owner) {
|
|
124
|
+
// delay just a bit so that it get received in sync load
|
|
125
|
+
setTimeout(() => {
|
|
126
|
+
owner.notify({ eventName: LottieViewBase.compositionLoadedEvent, composition });
|
|
127
|
+
// async loads arrive after the autoPlay property
|
|
128
|
+
// setter ran — playAnimation() there was a no-op on
|
|
129
|
+
// an empty view, so re-trigger on composition arrival.
|
|
130
|
+
if (owner.autoPlay && !owner.isAnimating()) {
|
|
131
|
+
owner.playAnimation();
|
|
132
|
+
}
|
|
133
|
+
}, 0);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
this.nativeViewProtected.addLottieOnCompositionLoadedListener(this.loadedListener);
|
|
139
|
+
const that = new WeakRef(this);
|
|
140
|
+
this.nativeViewProtected.setFailureListener(
|
|
141
|
+
new com.airbnb.lottie.LottieListener<java.lang.Throwable>({
|
|
142
|
+
onResult: (result) => {
|
|
143
|
+
const owner = that?.get();
|
|
144
|
+
if (owner) {
|
|
145
|
+
owner.notify({ eventName: LottieViewBase.loadFailedEvent, error: result });
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
})
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
public disposeNativeView(): void {
|
|
153
|
+
if (this.animatorListener) {
|
|
154
|
+
this.nativeViewProtected.removeAnimatorListener(this.animatorListener);
|
|
155
|
+
}
|
|
156
|
+
if (this.loadedListener) {
|
|
157
|
+
this.nativeViewProtected.removeLottieOnCompositionLoadedListener(this.loadedListener);
|
|
158
|
+
}
|
|
159
|
+
super.disposeNativeView();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
public setColor(value: Color | string, keyPath: string[]): void {
|
|
163
|
+
const nativeView = this.nativeViewProtected;
|
|
164
|
+
if (nativeView && value && keyPath && keyPath.length) {
|
|
165
|
+
if (keyPath[keyPath.length - 1].toLowerCase() === 'color') {
|
|
166
|
+
keyPath = [...keyPath];
|
|
167
|
+
keyPath.pop(); // android specifies the property as an enum parameter.
|
|
168
|
+
if (keyPath.length === 0) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
const nativeKeyPath: any[] = Array.create(java.lang.String, keyPath.length);
|
|
173
|
+
for (let index = 0; index < keyPath.length; index++) {
|
|
174
|
+
nativeKeyPath[index] = keyPath[index];
|
|
175
|
+
}
|
|
176
|
+
if (!LottieProperty) {
|
|
177
|
+
LottieProperty = com.airbnb.lottie.LottieProperty;
|
|
178
|
+
}
|
|
179
|
+
if (!LottieValueCallback) {
|
|
180
|
+
LottieValueCallback = com.airbnb.lottie.value.LottieValueCallback;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (!LottieKeyPath) {
|
|
184
|
+
LottieKeyPath = com.airbnb.lottie.model.KeyPath;
|
|
185
|
+
}
|
|
186
|
+
// by using color filter we change all colors (STROKE_COLOR and COLOR)
|
|
187
|
+
const color = value instanceof Color ? value : new Color(value);
|
|
188
|
+
// const colorFilter = new android.graphics.PorterDuffColorFilter(value.android, android.graphics.PorterDuff.Mode.SRC_ATOP) ;
|
|
189
|
+
const colorFilter = new com.airbnb.lottie.SimpleColorFilter(color.android);
|
|
190
|
+
nativeView.addValueCallback(new LottieKeyPath(nativeKeyPath as any), LottieProperty.COLOR_FILTER, new LottieValueCallback(colorFilter));
|
|
191
|
+
// nativeView.addValueCallback(
|
|
192
|
+
// new LottieKeyPath(nativeKeyPath as any),
|
|
193
|
+
// LottieProperty.COLOR,
|
|
194
|
+
// new LottieValueCallback(java.lang.Integer.valueOf(value.android))
|
|
195
|
+
// );
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
public setOpacity(value: number, keyPath: string[]): void {
|
|
200
|
+
if (this.nativeViewProtected && value != null && keyPath && keyPath.length) {
|
|
201
|
+
if (keyPath[keyPath.length - 1].toLowerCase() === 'opacity') {
|
|
202
|
+
keyPath = [...keyPath];
|
|
203
|
+
keyPath.pop(); // android specifies the property as an enum parameter.
|
|
204
|
+
if (keyPath.length === 0) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
const nativeKeyPath: java.lang.String[] = Array.create(java.lang.String, keyPath.length);
|
|
209
|
+
keyPath.forEach((key, index) => {
|
|
210
|
+
nativeKeyPath[index] = new java.lang.String(key);
|
|
211
|
+
});
|
|
212
|
+
value = clamp(value);
|
|
213
|
+
if (!LottieProperty) {
|
|
214
|
+
LottieProperty = com.airbnb.lottie.LottieProperty;
|
|
215
|
+
}
|
|
216
|
+
if (!LottieValueCallback) {
|
|
217
|
+
LottieValueCallback = com.airbnb.lottie.value.LottieValueCallback;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (!LottieKeyPath) {
|
|
221
|
+
LottieKeyPath = com.airbnb.lottie.model.KeyPath;
|
|
222
|
+
}
|
|
223
|
+
// LottieProperty.OPACITY is an Integer on a 0–255 scale (matching
|
|
224
|
+
// Paint#setAlpha), not a 0–100 percentage.
|
|
225
|
+
this.nativeViewProtected.addValueCallback(new LottieKeyPath(nativeKeyPath as any), LottieProperty.OPACITY, new LottieValueCallback(new java.lang.Integer(value * 255)));
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
public playAnimation(): void {
|
|
230
|
+
if (this.nativeViewProtected) {
|
|
231
|
+
this.nativeViewProtected.setMinAndMaxProgress(0, 1);
|
|
232
|
+
this.nativeViewProtected.playAnimation();
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
public playAnimationFromProgressToProgress(startProgress: number, endProgress: number): void {
|
|
237
|
+
if (this.nativeViewProtected) {
|
|
238
|
+
startProgress = startProgress ? clamp(startProgress) : 0;
|
|
239
|
+
endProgress = endProgress ? clamp(endProgress) : 1;
|
|
240
|
+
this.nativeViewProtected.setMinAndMaxProgress(startProgress, endProgress);
|
|
241
|
+
this.nativeViewProtected.playAnimation();
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
public isAnimating(): boolean {
|
|
246
|
+
return this.nativeViewProtected ? this.nativeViewProtected.isAnimating() : false;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
public get speed(): number | undefined {
|
|
250
|
+
return this.nativeViewProtected ? this.nativeViewProtected.getSpeed() : undefined;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
public set speed(value: number) {
|
|
254
|
+
if (this.nativeViewProtected && value) {
|
|
255
|
+
this.nativeViewProtected.setSpeed(value);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
public get duration(): number | undefined {
|
|
260
|
+
return this.nativeViewProtected ? this.nativeViewProtected.getDuration() : undefined;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
public cancelAnimation(): void {
|
|
264
|
+
if (this.nativeViewProtected) {
|
|
265
|
+
this.nativeViewProtected.cancelAnimation();
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
public pauseAnimation(): void {
|
|
270
|
+
if (this.nativeViewProtected) {
|
|
271
|
+
this.nativeViewProtected.pauseAnimation();
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
public resumeAnimation(): void {
|
|
276
|
+
if (this.nativeViewProtected) {
|
|
277
|
+
this.nativeViewProtected.resumeAnimation();
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
[srcProperty.setNative](src: string) {
|
|
282
|
+
try {
|
|
283
|
+
if (!LottieCompositionFactory) {
|
|
284
|
+
LottieCompositionFactory = com.airbnb.lottie.LottieCompositionFactory;
|
|
285
|
+
}
|
|
286
|
+
const view = this.nativeViewProtected;
|
|
287
|
+
let result: com.airbnb.lottie.LottieResult<com.airbnb.lottie.LottieComposition>;
|
|
288
|
+
if (!src) {
|
|
289
|
+
// lottie does not support "clearing the animation"
|
|
290
|
+
// view.setAnimation(null);
|
|
291
|
+
} else if (src[0] === '{') {
|
|
292
|
+
if (this.async) {
|
|
293
|
+
view.setAnimationFromJson(src, null);
|
|
294
|
+
} else {
|
|
295
|
+
result = LottieCompositionFactory.fromJsonStringSync(src, null);
|
|
296
|
+
}
|
|
297
|
+
} else if (/^https?:/i.test(src)) {
|
|
298
|
+
// Remote URL — download to a temp file and re-enter as a
|
|
299
|
+
// local path. (Android could use LottieCompositionFactory.
|
|
300
|
+
// fromUrl, but the download path works identically on iOS
|
|
301
|
+
// and flows failures through loadFailed.)
|
|
302
|
+
const match = /\.(zip|lottie|json)(?=[?#]|$)/i.exec(src);
|
|
303
|
+
const dest = path.join(knownFolders.temp().path, `lottie-${Date.now()}${match ? match[0].toLowerCase() : '.json'}`);
|
|
304
|
+
Http.getFile(src, dest)
|
|
305
|
+
.then(() => {
|
|
306
|
+
this.src = dest;
|
|
307
|
+
})
|
|
308
|
+
.catch((error) => {
|
|
309
|
+
console.error(error);
|
|
310
|
+
this.notify({ eventName: 'loadFailed', error });
|
|
311
|
+
});
|
|
312
|
+
} else if (src.startsWith(Utils.RESOURCE_PREFIX)) {
|
|
313
|
+
const resName = src.replace(Utils.RESOURCE_PREFIX, '');
|
|
314
|
+
if (this.async) {
|
|
315
|
+
view.setAnimation(resName);
|
|
316
|
+
} else {
|
|
317
|
+
result = com.airbnb.lottie.LottieCompositionFactory.fromAssetSync(this._context, resName);
|
|
318
|
+
}
|
|
319
|
+
} else {
|
|
320
|
+
if (!/.(json|zip|lottie)$/.test(src)) {
|
|
321
|
+
src += '.json';
|
|
322
|
+
}
|
|
323
|
+
if (src[0] === '~') {
|
|
324
|
+
if (this.async) {
|
|
325
|
+
view.setAnimation('app/' + src.substring(2));
|
|
326
|
+
} else {
|
|
327
|
+
result = com.airbnb.lottie.LottieCompositionFactory.fromAssetSync(this._context, 'app/' + src.substring(2));
|
|
328
|
+
}
|
|
329
|
+
} else if (!src.startsWith('file:/') && src[0] !== '/') {
|
|
330
|
+
if (this.async) {
|
|
331
|
+
view.setAnimation('app/' + src);
|
|
332
|
+
} else {
|
|
333
|
+
result = com.airbnb.lottie.LottieCompositionFactory.fromAssetSync(this._context, src);
|
|
334
|
+
}
|
|
335
|
+
} else {
|
|
336
|
+
const filePath = src.startsWith('file:') ? src.substring('file:'.length) : src;
|
|
337
|
+
if (/\.(zip|lottie)$/i.test(filePath)) {
|
|
338
|
+
// Binary containers can't survive File.readText — hand
|
|
339
|
+
// a ZipInputStream to the factory instead.
|
|
340
|
+
const stream = new java.util.zip.ZipInputStream(new java.io.FileInputStream(filePath));
|
|
341
|
+
if (this.async) {
|
|
342
|
+
const owner = new WeakRef(this);
|
|
343
|
+
com.airbnb.lottie.LottieCompositionFactory.fromZipStream(stream, null)
|
|
344
|
+
.addListener(
|
|
345
|
+
new com.airbnb.lottie.LottieListener<com.airbnb.lottie.LottieComposition>({
|
|
346
|
+
onResult: (composition) => {
|
|
347
|
+
const view = owner.get()?.nativeViewProtected;
|
|
348
|
+
if (view) {
|
|
349
|
+
view.setComposition(composition);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
})
|
|
353
|
+
)
|
|
354
|
+
.addFailureListener(
|
|
355
|
+
new com.airbnb.lottie.LottieListener<java.lang.Throwable>({
|
|
356
|
+
onResult: (error) => console.error(error)
|
|
357
|
+
})
|
|
358
|
+
);
|
|
359
|
+
} else {
|
|
360
|
+
result = com.airbnb.lottie.LottieCompositionFactory.fromZipStreamSync(stream, null);
|
|
361
|
+
}
|
|
362
|
+
} else if (this.async) {
|
|
363
|
+
loadLottieJSON(src).then((result) => {
|
|
364
|
+
if (this.nativeViewProtected) {
|
|
365
|
+
this.nativeViewProtected.setAnimationFromJson(result, null);
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
} else {
|
|
369
|
+
result = LottieCompositionFactory.fromJsonStringSync(loadLottieJSONSync(src), null);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
if (result) {
|
|
374
|
+
if (result.getException()) {
|
|
375
|
+
console.error(result.getException());
|
|
376
|
+
this.notify({ eventName: LottieViewBase.loadFailedEvent, error: result.getException() });
|
|
377
|
+
// view.setComposition(null);
|
|
378
|
+
} else {
|
|
379
|
+
view.setComposition(result.getValue());
|
|
380
|
+
|
|
381
|
+
//in sync loading we need to fire it ourselves
|
|
382
|
+
// if we dont differ it from now it wont be received
|
|
383
|
+
// setTimeout(() => {
|
|
384
|
+
// this.notify({ eventName: 'compositionLoaded', composition: result.getValue() });
|
|
385
|
+
// }, 0);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
if (this.autoPlay) {
|
|
389
|
+
this.playAnimation();
|
|
390
|
+
}
|
|
391
|
+
} catch (error) {
|
|
392
|
+
console.error(error);
|
|
393
|
+
this.notify({ eventName: LottieViewBase.loadFailedEvent, error });
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
[loopProperty.setNative](loop: boolean) {
|
|
398
|
+
this.nativeViewProtected.setRepeatCount(loop ? -1 /* android.animation.ValueAnimator.INFINITE */ : 0);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
[progressProperty.setNative](value: number) {
|
|
402
|
+
this.nativeViewProtected.setProgress(value);
|
|
403
|
+
}
|
|
404
|
+
[renderModeProperty.setNative](renderMode) {
|
|
405
|
+
this.nativeViewProtected.setRenderMode(renderMode);
|
|
406
|
+
}
|
|
407
|
+
[keyPathColorsProperty.setNative](value) {
|
|
408
|
+
Object.keys(value).forEach((k) => this.setColor(value[k], k.split('|')));
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
[autoPlayProperty.setNative](autoPlay: boolean) {
|
|
412
|
+
if (autoPlay) {
|
|
413
|
+
if (!this.isAnimating()) {
|
|
414
|
+
this.playAnimation();
|
|
415
|
+
}
|
|
416
|
+
} else {
|
|
417
|
+
// disable check for now as isAnimating always returns false
|
|
418
|
+
// if (this.isAnimating()) {
|
|
419
|
+
this.cancelAnimation();
|
|
420
|
+
if (this.progress) {
|
|
421
|
+
this.nativeViewProtected.setProgress(this.progress);
|
|
422
|
+
}
|
|
423
|
+
// }
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
[stretchProperty.getDefault](): 'aspectFit' {
|
|
428
|
+
return 'aspectFit';
|
|
429
|
+
}
|
|
430
|
+
[stretchProperty.setNative](value: 'none' | 'aspectFill' | 'aspectFit' | 'fill') {
|
|
431
|
+
switch (value) {
|
|
432
|
+
case 'aspectFit':
|
|
433
|
+
this.nativeViewProtected.setScaleType(android.widget.ImageView.ScaleType.FIT_CENTER);
|
|
434
|
+
break;
|
|
435
|
+
case 'aspectFill':
|
|
436
|
+
this.nativeViewProtected.setScaleType(android.widget.ImageView.ScaleType.CENTER_CROP);
|
|
437
|
+
break;
|
|
438
|
+
case 'fill':
|
|
439
|
+
this.nativeViewProtected.setScaleType(android.widget.ImageView.ScaleType.FIT_XY);
|
|
440
|
+
break;
|
|
441
|
+
case 'none':
|
|
442
|
+
default:
|
|
443
|
+
this.nativeViewProtected.setScaleType(android.widget.ImageView.ScaleType.MATRIX);
|
|
444
|
+
break;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**********************************************************************************
|
|
2
|
+
* (c) 2017, Nathan Walker.
|
|
3
|
+
* Licensed under the MIT license.
|
|
4
|
+
*
|
|
5
|
+
* Version 1.0.0 walkerrunpdx@gmail.com
|
|
6
|
+
**********************************************************************************/
|
|
7
|
+
|
|
8
|
+
// Vendored from @nativescript-community/ui-lottie (MIT), fork branch
|
|
9
|
+
// xplat-fixes on octane-xplat/ui-lottie — device-probed fixes for dead
|
|
10
|
+
// sync-src, missing events/pause-resume, URL/.lottie sources, async
|
|
11
|
+
// autoPlay, completion dedupe, opacity scale, Podfile pin.
|
|
12
|
+
// @ts-nocheck — vendored upstream code, not strict-clean. Kept
|
|
13
|
+
// close to the fork so fix branches stay PR-able; divergences are
|
|
14
|
+
// commented inline.
|
|
15
|
+
import { CoreTypes, Property, View, booleanConverter } from '@nativescript/core';
|
|
16
|
+
// KeyPathColors lives here — upstream's `from '.'` self-import
|
|
17
|
+
// doesn't resolve in a vendored layout.
|
|
18
|
+
export interface KeyPathColors {
|
|
19
|
+
[k: string]: Color | string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class LottieViewBase extends View {
|
|
23
|
+
public static compositionLoadedEvent = 'compositionLoaded';
|
|
24
|
+
public static loadFailedEvent = 'loadFailed';
|
|
25
|
+
// `declare`, not plain fields — under useDefineForClassFields (esbuild/
|
|
26
|
+
// rolldown, es2022+) plain declarations emit instance fields that shadow
|
|
27
|
+
// the Property accessors register() installs, silently breaking every
|
|
28
|
+
// property set. Upstream's tsc emit never hit this; vendored fork fix.
|
|
29
|
+
public declare stretch: CoreTypes.ImageStretchType;
|
|
30
|
+
public declare async: boolean;
|
|
31
|
+
public declare src: string;
|
|
32
|
+
public declare loop: boolean;
|
|
33
|
+
public declare autoPlay: boolean;
|
|
34
|
+
public declare progress: number;
|
|
35
|
+
public declare keyPathColors: KeyPathColors;
|
|
36
|
+
public declare completionBlock: (animationFinished: boolean) => void;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const srcProperty = new Property<LottieViewBase, string>({
|
|
40
|
+
name: 'src'
|
|
41
|
+
});
|
|
42
|
+
srcProperty.register(LottieViewBase);
|
|
43
|
+
|
|
44
|
+
export const asyncProperty = new Property<LottieViewBase, boolean>({
|
|
45
|
+
name: 'async',
|
|
46
|
+
defaultValue: false,
|
|
47
|
+
valueConverter: booleanConverter
|
|
48
|
+
});
|
|
49
|
+
asyncProperty.register(LottieViewBase);
|
|
50
|
+
export const loopProperty = new Property<LottieViewBase, boolean>({
|
|
51
|
+
name: 'loop',
|
|
52
|
+
defaultValue: false,
|
|
53
|
+
valueConverter: booleanConverter
|
|
54
|
+
});
|
|
55
|
+
loopProperty.register(LottieViewBase);
|
|
56
|
+
|
|
57
|
+
export const autoPlayProperty = new Property<LottieViewBase, boolean>({
|
|
58
|
+
name: 'autoPlay',
|
|
59
|
+
defaultValue: false,
|
|
60
|
+
valueConverter: booleanConverter
|
|
61
|
+
});
|
|
62
|
+
autoPlayProperty.register(LottieViewBase);
|
|
63
|
+
|
|
64
|
+
export const renderModeProperty = new Property<LottieViewBase, number>({
|
|
65
|
+
name: 'renderMode'
|
|
66
|
+
});
|
|
67
|
+
renderModeProperty.register(LottieViewBase);
|
|
68
|
+
|
|
69
|
+
export const progressProperty = new Property<LottieViewBase, number>({
|
|
70
|
+
name: 'progress'
|
|
71
|
+
});
|
|
72
|
+
progressProperty.register(LottieViewBase);
|
|
73
|
+
|
|
74
|
+
export const stretchProperty = new Property<LottieViewBase, CoreTypes.ImageStretchType>({
|
|
75
|
+
name: 'stretch',
|
|
76
|
+
defaultValue: 'aspectFit',
|
|
77
|
+
affectsLayout: global.isIOS
|
|
78
|
+
});
|
|
79
|
+
stretchProperty.register(LottieViewBase);
|
|
80
|
+
|
|
81
|
+
export const keyPathColorsProperty = new Property<LottieViewBase, KeyPathColors>({
|
|
82
|
+
name: 'keyPathColors'
|
|
83
|
+
});
|
|
84
|
+
keyPathColorsProperty.register(LottieViewBase);
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { Color, View } from '@nativescript/core';
|
|
2
|
+
|
|
3
|
+
export enum RenderMode {
|
|
4
|
+
AUTOMATIC,
|
|
5
|
+
HARDWARE,
|
|
6
|
+
SOFTWARE
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface KeyPathColors {
|
|
10
|
+
[k: string]: Color | string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class LottieView extends View {
|
|
14
|
+
/**
|
|
15
|
+
* The composition finished loading. `event.composition` is the native
|
|
16
|
+
* composition object.
|
|
17
|
+
*/
|
|
18
|
+
static compositionLoadedEvent: string;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The src failed to load or parse. `event.error` carries the failure.
|
|
22
|
+
*/
|
|
23
|
+
static loadFailedEvent: string;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* LottieAnimationView
|
|
27
|
+
*/
|
|
28
|
+
readonly android: any;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* AnimationView
|
|
32
|
+
*/
|
|
33
|
+
readonly ios: any;
|
|
34
|
+
|
|
35
|
+
constructor();
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Flag determining whether the animation should start playing as soon as the view is ready.
|
|
39
|
+
*/
|
|
40
|
+
autoPlay: boolean;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Block to be executed upon completion of the animation.
|
|
44
|
+
* The animation is considered complete when it finishes playing and is no longer looping.
|
|
45
|
+
*/
|
|
46
|
+
completionBlock: (animationFinished: boolean) => void;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* (iOS only) The current UIViewContentMode.
|
|
50
|
+
*/
|
|
51
|
+
contentMode: any;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* The duration of the animation.
|
|
55
|
+
*/
|
|
56
|
+
readonly duration: number | undefined;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Flag determining whether the animation should loop or not.
|
|
60
|
+
*/
|
|
61
|
+
loop: boolean;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Load the source asynchronously instead of blocking the main thread
|
|
65
|
+
* (Android only — iOS always resolves synchronously).
|
|
66
|
+
*/
|
|
67
|
+
async: boolean;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* How the animation scales inside the view's bounds — NativeScript's
|
|
71
|
+
* ImageStretchType ('none' | 'fill' | 'aspectFit' | 'aspectFill').
|
|
72
|
+
*/
|
|
73
|
+
stretch: string;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* The current progress of the animation.
|
|
77
|
+
*/
|
|
78
|
+
progress: number | undefined;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* The current speed of the animation.
|
|
82
|
+
*/
|
|
83
|
+
speed: number | undefined;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* The current source of the animation. Accepts inline JSON (string
|
|
87
|
+
* starting with '{'), res:// resource names, ~/ app paths, absolute
|
|
88
|
+
* file paths, and http(s) URLs (downloaded to a temp file).
|
|
89
|
+
*/
|
|
90
|
+
src: string | undefined;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* (Android) Cancels the animation.
|
|
94
|
+
*
|
|
95
|
+
* (iOS) Pauses the animation.
|
|
96
|
+
*/
|
|
97
|
+
cancelAnimation(): void;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Pauses the animation, keeping the current progress.
|
|
101
|
+
*/
|
|
102
|
+
pauseAnimation(): void;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Resumes the animation from where it was paused.
|
|
106
|
+
*/
|
|
107
|
+
resumeAnimation(): void;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Returns true if the view is currently animating.
|
|
111
|
+
*/
|
|
112
|
+
isAnimating(): boolean;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Sets the provided color value on each property that matches the specified keyPath.
|
|
116
|
+
*/
|
|
117
|
+
setColor(value: Color, keyPath: string[]): void;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Sets the provided opacity value on each property that matches the specified keyPath.
|
|
121
|
+
*/
|
|
122
|
+
setOpacity(value: number, keyPath: string[]): void;
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Plays the animation from the beginning.
|
|
126
|
+
*/
|
|
127
|
+
playAnimation(): void;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Plays the animation from the specified start and end progress values (between 0 and 1).
|
|
131
|
+
*/
|
|
132
|
+
playAnimationFromProgressToProgress(startProgress: number, endProgress: number): void;
|
|
133
|
+
}
|