@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
package/README.md
CHANGED
|
@@ -1,3 +1,37 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `@octane-xplat/lottie`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Lottie animations for Octane xplat apps: `lottie-web`'s svg renderer on
|
|
4
|
+
web and a vendored fork of `@nativescript-community/ui-lottie` on native
|
|
5
|
+
(`src/vendor/ui-lottie` submodule — the leaf _is_ the plugin via
|
|
6
|
+
`nativescript.platforms`, so no separate plugin install).
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
pnpm add @octane-xplat/lottie
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
```tsx
|
|
13
|
+
import { Lottie } from '@octane-xplat/lottie'
|
|
14
|
+
|
|
15
|
+
;<Lottie
|
|
16
|
+
src="https://example.com/anim.json" // native also takes ~/, res://, .lottie/.zip, or raw JSON
|
|
17
|
+
autoPlay // default true
|
|
18
|
+
loop // default false — a finite play is the shared contract
|
|
19
|
+
fit="contain" // 'contain' | 'cover' | 'fill'
|
|
20
|
+
onLoaded={(e) => console.log(e.duration)}
|
|
21
|
+
onEnded={() => console.log('done')}
|
|
22
|
+
bind={(h) => (handle = h)} // play/pause/stop/seekTo(0..1)/setSpeed + .native
|
|
23
|
+
/>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
`data` (an inline animation object) wins over `src` when both are given.
|
|
27
|
+
Controlled `playing`/`progress`/`speed` props are optional — unset, the
|
|
28
|
+
animation is uncontrolled and the `bind` handle still drives it. Progress
|
|
29
|
+
is always normalized 0..1 and durations are milliseconds on every target
|
|
30
|
+
(the iOS plugin natively reports seconds; the leaf normalizes).
|
|
31
|
+
|
|
32
|
+
Per-target limits — including the expression/CSP boundary on web — are
|
|
33
|
+
recorded in [known limits](../../docs/known-limits.md). Exercised by
|
|
34
|
+
[`LottieDemo`](../demos/src/LottieDemo.tsrx).
|
|
35
|
+
|
|
36
|
+
This is a git submodule checkout: after cloning run
|
|
37
|
+
`git submodule update --init` before building the workspace.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/cx.mobile.ts
|
|
2
|
+
/** NS `className` splits on ' ' only, and the universal driver applies the
|
|
3
|
+
* prop via `String(value)` — an array would arrive comma-joined and match
|
|
4
|
+
* no class at all. Native leaves normalize through cx() before handing
|
|
5
|
+
* className to an intrinsic. (The DOM renderer already flattens arrays,
|
|
6
|
+
* so web leaves don't need this.) */
|
|
7
|
+
function cx(...parts) {
|
|
8
|
+
return parts.flat(Infinity).filter(Boolean).join(" ");
|
|
9
|
+
}
|
|
10
|
+
//#endregion
|
|
11
|
+
export { cx };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { isAndroid, isIOS } from "@nativescript/core";
|
|
2
|
+
//#region src/escape-props.ts
|
|
3
|
+
/** Apply only the active device's escape bag after the primitive's own props. */
|
|
4
|
+
function applyEscapeProps(view, props) {
|
|
5
|
+
if (!view) return;
|
|
6
|
+
const bag = isIOS ? props.ios : isAndroid ? props.android : void 0;
|
|
7
|
+
if (bag) Object.assign(view, bag);
|
|
8
|
+
}
|
|
9
|
+
var NATIVE_ACCESSIBILITY_ROLES = {
|
|
10
|
+
button: "button",
|
|
11
|
+
link: "link",
|
|
12
|
+
search: "search",
|
|
13
|
+
image: "image",
|
|
14
|
+
heading: "header",
|
|
15
|
+
adjustable: "adjustable",
|
|
16
|
+
summary: "summary",
|
|
17
|
+
text: "text",
|
|
18
|
+
none: "none",
|
|
19
|
+
progressbar: "progressBar",
|
|
20
|
+
checkbox: "checkbox",
|
|
21
|
+
switch: "switch",
|
|
22
|
+
radio: "radioButton",
|
|
23
|
+
spinbutton: "spinButton",
|
|
24
|
+
tab: "button"
|
|
25
|
+
};
|
|
26
|
+
/** Translate the shared/ARIA spelling to NativeScript's narrower role enum. */
|
|
27
|
+
function nativeAccessibilityRole(role) {
|
|
28
|
+
return role ? NATIVE_ACCESSIBILITY_ROLES[role] : void 0;
|
|
29
|
+
}
|
|
30
|
+
/** NativeScript's AccessibilityState is a single enum value, unlike the
|
|
31
|
+
* web's independent ARIA booleans. Priority follows the strongest state. */
|
|
32
|
+
function nativeAccessibilityState(state) {
|
|
33
|
+
if (state?.disabled) return "disabled";
|
|
34
|
+
if (state?.selected) return "selected";
|
|
35
|
+
if (state?.checked === true) return "checked";
|
|
36
|
+
if (state?.checked === false) return "unchecked";
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
export { applyEscapeProps, nativeAccessibilityRole, nativeAccessibilityState };
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { cx } from "./cx.mobile.js";
|
|
2
|
+
import { applyEscapeProps, nativeAccessibilityRole, nativeAccessibilityState } from "./escape-props.js";
|
|
3
|
+
import { layoutChildProps } from "./layout-child.js";
|
|
4
|
+
import { defineUniversalComponent, hookSlots, registerElement, universalPlan, universalProps, universalValue, useCallback, useEffect, useRef } from "@nativescript-community/octane";
|
|
5
|
+
import { isAndroid } from "@nativescript/core";
|
|
6
|
+
import { LottieView } from "./vendor/ui-lottie";
|
|
7
|
+
//#region src/Lottie.tsrx
|
|
8
|
+
var _hs$ = /* @__PURE__ */ hookSlots(9);
|
|
9
|
+
var _h$0 = /* @__PURE__ */ Symbol(_hs$);
|
|
10
|
+
var _h$1 = /* @__PURE__ */ Symbol(_hs$ + 1);
|
|
11
|
+
var _h$2 = /* @__PURE__ */ Symbol(_hs$ + 2);
|
|
12
|
+
var _h$3 = /* @__PURE__ */ Symbol(_hs$ + 3);
|
|
13
|
+
var _h$4 = /* @__PURE__ */ Symbol(_hs$ + 4);
|
|
14
|
+
var _h$5 = /* @__PURE__ */ Symbol(_hs$ + 5);
|
|
15
|
+
var _h$6 = /* @__PURE__ */ Symbol(_hs$ + 6);
|
|
16
|
+
var _h$7 = /* @__PURE__ */ Symbol(_hs$ + 7);
|
|
17
|
+
var _h$8 = /* @__PURE__ */ Symbol(_hs$ + 8);
|
|
18
|
+
var __octaneUniversalPlan0 = universalPlan("nativescript", {
|
|
19
|
+
"kind": "host",
|
|
20
|
+
"type": "xplatlottie",
|
|
21
|
+
"propsSlot": 0
|
|
22
|
+
});
|
|
23
|
+
registerElement("xplatlottie", LottieView);
|
|
24
|
+
var clamp01 = (n) => Math.min(1, Math.max(0, n));
|
|
25
|
+
var STRETCH = {
|
|
26
|
+
contain: "aspectFit",
|
|
27
|
+
cover: "aspectFill",
|
|
28
|
+
fill: "fill"
|
|
29
|
+
};
|
|
30
|
+
function durationMs(v) {
|
|
31
|
+
const d = v.duration ?? 0;
|
|
32
|
+
return isAndroid ? d : Math.max(0, d) * 1e3;
|
|
33
|
+
}
|
|
34
|
+
function currentProgress(v) {
|
|
35
|
+
const nv = v.nativeViewProtected;
|
|
36
|
+
return isAndroid ? nv?.getProgress?.() ?? 0 : nv?.currentProgress ?? 0;
|
|
37
|
+
}
|
|
38
|
+
function stopView(v) {
|
|
39
|
+
if (isAndroid) v.cancelAnimation();
|
|
40
|
+
else v.nativeViewProtected?.stop();
|
|
41
|
+
v.progress = 0;
|
|
42
|
+
}
|
|
43
|
+
var Lottie = defineUniversalComponent("nativescript", function Lottie(props) {
|
|
44
|
+
const host = useRef(null, _h$0);
|
|
45
|
+
const appliedSrc = useRef(void 0, _h$1);
|
|
46
|
+
const loadedRef = useRef(false, _h$2);
|
|
47
|
+
const bindHost = useCallback((v) => {
|
|
48
|
+
host.current = v;
|
|
49
|
+
}, [], _h$3);
|
|
50
|
+
const wantPlay = () => props.playing ?? props.autoPlay ?? true;
|
|
51
|
+
const onReady = () => {
|
|
52
|
+
const v = host.current;
|
|
53
|
+
if (!v || loadedRef.current) return;
|
|
54
|
+
loadedRef.current = true;
|
|
55
|
+
if (props.speed !== void 0) v.speed = props.speed;
|
|
56
|
+
if (props.progress !== void 0) v.progress = clamp01(props.progress);
|
|
57
|
+
props.onLoaded?.({ duration: durationMs(v) });
|
|
58
|
+
if (wantPlay() && !v.isAnimating()) v.playAnimation();
|
|
59
|
+
};
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
const v = host.current;
|
|
62
|
+
if (!v) return;
|
|
63
|
+
applyEscapeProps(v, props);
|
|
64
|
+
v.stretch = STRETCH[props.fit ?? "contain"];
|
|
65
|
+
v.async = true;
|
|
66
|
+
v.on(LottieView.compositionLoadedEvent, () => onReady());
|
|
67
|
+
v.on(LottieView.loadFailedEvent, (e) => {
|
|
68
|
+
loadedRef.current = false;
|
|
69
|
+
props.onError?.({ message: e?.error ? String(e.error) : "load failed" });
|
|
70
|
+
});
|
|
71
|
+
v.completionBlock = (finished) => {
|
|
72
|
+
if (finished) props.onEnded?.();
|
|
73
|
+
};
|
|
74
|
+
props.bind?.(handle(v));
|
|
75
|
+
}, [], _h$4);
|
|
76
|
+
useEffect(() => {
|
|
77
|
+
const v = host.current;
|
|
78
|
+
if (!v) return;
|
|
79
|
+
const src = props.data ? JSON.stringify(props.data) : props.src;
|
|
80
|
+
if (src === appliedSrc.current) return;
|
|
81
|
+
appliedSrc.current = src;
|
|
82
|
+
loadedRef.current = false;
|
|
83
|
+
v.src = src ?? "";
|
|
84
|
+
}, [props.src, props.data], _h$5);
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
const v = host.current;
|
|
87
|
+
if (!v || props.playing === void 0) return;
|
|
88
|
+
if (props.playing) {
|
|
89
|
+
if (loadedRef.current) v.resumeAnimation();
|
|
90
|
+
} else v.pauseAnimation();
|
|
91
|
+
}, [props.playing], _h$6);
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
const v = host.current;
|
|
94
|
+
if (!v || props.progress === void 0 || !loadedRef.current) return;
|
|
95
|
+
v.progress = clamp01(props.progress);
|
|
96
|
+
}, [props.progress], _h$7);
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
const v = host.current;
|
|
99
|
+
if (!v || props.speed === void 0 || !loadedRef.current) return;
|
|
100
|
+
v.speed = props.speed;
|
|
101
|
+
}, [props.speed], _h$8);
|
|
102
|
+
const handle = (v) => ({
|
|
103
|
+
play: () => v.resumeAnimation(),
|
|
104
|
+
pause: () => v.pauseAnimation(),
|
|
105
|
+
stop: () => stopView(v),
|
|
106
|
+
seekTo: (p) => {
|
|
107
|
+
v.progress = clamp01(p);
|
|
108
|
+
},
|
|
109
|
+
setSpeed: (n) => {
|
|
110
|
+
v.speed = n;
|
|
111
|
+
},
|
|
112
|
+
progress: () => currentProgress(v),
|
|
113
|
+
duration: () => durationMs(v),
|
|
114
|
+
isPlaying: () => v.isAnimating(),
|
|
115
|
+
native: v
|
|
116
|
+
});
|
|
117
|
+
return universalValue(__octaneUniversalPlan0, [universalProps([
|
|
118
|
+
[
|
|
119
|
+
"set",
|
|
120
|
+
"ref",
|
|
121
|
+
bindHost
|
|
122
|
+
],
|
|
123
|
+
[
|
|
124
|
+
"set",
|
|
125
|
+
"id",
|
|
126
|
+
props.id
|
|
127
|
+
],
|
|
128
|
+
[
|
|
129
|
+
"set",
|
|
130
|
+
"className",
|
|
131
|
+
cx(props.className)
|
|
132
|
+
],
|
|
133
|
+
[
|
|
134
|
+
"set",
|
|
135
|
+
"style",
|
|
136
|
+
props.style
|
|
137
|
+
],
|
|
138
|
+
["spread", layoutChildProps(props)],
|
|
139
|
+
[
|
|
140
|
+
"set",
|
|
141
|
+
"loop",
|
|
142
|
+
props.loop ?? false
|
|
143
|
+
],
|
|
144
|
+
[
|
|
145
|
+
"set",
|
|
146
|
+
"accessible",
|
|
147
|
+
props.accessible
|
|
148
|
+
],
|
|
149
|
+
[
|
|
150
|
+
"set",
|
|
151
|
+
"accessibilityLabel",
|
|
152
|
+
props.accessibilityLabel
|
|
153
|
+
],
|
|
154
|
+
[
|
|
155
|
+
"set",
|
|
156
|
+
"accessibilityRole",
|
|
157
|
+
nativeAccessibilityRole(props.accessibilityRole)
|
|
158
|
+
],
|
|
159
|
+
[
|
|
160
|
+
"set",
|
|
161
|
+
"accessibilityHint",
|
|
162
|
+
props.accessibilityHint
|
|
163
|
+
],
|
|
164
|
+
[
|
|
165
|
+
"set",
|
|
166
|
+
"accessibilityValue",
|
|
167
|
+
props.accessibilityValue
|
|
168
|
+
],
|
|
169
|
+
[
|
|
170
|
+
"set",
|
|
171
|
+
"accessibilityState",
|
|
172
|
+
nativeAccessibilityState(props.accessibilityState)
|
|
173
|
+
],
|
|
174
|
+
[
|
|
175
|
+
"set",
|
|
176
|
+
"accessibilityLiveRegion",
|
|
177
|
+
props.accessibilityLiveRegion
|
|
178
|
+
]
|
|
179
|
+
])]);
|
|
180
|
+
}, { "module": "@nativescript-community/octane" });
|
|
181
|
+
//#endregion
|
|
182
|
+
export { Lottie };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
//#region src/layout-child.ts
|
|
2
|
+
var FLEX_JUSTIFY = {
|
|
3
|
+
start: "flex-start",
|
|
4
|
+
end: "flex-end"
|
|
5
|
+
};
|
|
6
|
+
var FLEX_ALIGN = {
|
|
7
|
+
start: "flex-start",
|
|
8
|
+
end: "flex-end"
|
|
9
|
+
};
|
|
10
|
+
/** NativeScript reads these attributes from each child view during parent
|
|
11
|
+
* layout. Values are forwarded with NativeScript's own property names.
|
|
12
|
+
* The flex-container props (justifyContent/alignItems/flexWrap/gap) land on
|
|
13
|
+
* the host flexboxlayout itself — its own attributes, not child metadata. */
|
|
14
|
+
function layoutChildProps(props) {
|
|
15
|
+
const result = {};
|
|
16
|
+
for (const key of [
|
|
17
|
+
"row",
|
|
18
|
+
"col",
|
|
19
|
+
"rowSpan",
|
|
20
|
+
"colSpan",
|
|
21
|
+
"dock",
|
|
22
|
+
"left",
|
|
23
|
+
"top",
|
|
24
|
+
"flexGrow",
|
|
25
|
+
"flexShrink",
|
|
26
|
+
"alignSelf",
|
|
27
|
+
"order"
|
|
28
|
+
]) if (props[key] !== void 0) result[key] = props[key];
|
|
29
|
+
if (props.justifyContent !== void 0) result.justifyContent = FLEX_JUSTIFY[props.justifyContent] ?? props.justifyContent;
|
|
30
|
+
if (props.alignItems !== void 0) result.alignItems = FLEX_ALIGN[props.alignItems] ?? props.alignItems;
|
|
31
|
+
if (props.flexWrap !== void 0) result.flexWrap = props.flexWrap === true ? "wrap" : props.flexWrap === false ? "nowrap" : props.flexWrap;
|
|
32
|
+
if (props.gap !== void 0) result.gap = props.gap;
|
|
33
|
+
if (props.rowGap !== void 0) result.rowGap = props.rowGap;
|
|
34
|
+
if (props.columnGap !== void 0) result.columnGap = props.columnGap;
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
38
|
+
export { layoutChildProps };
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import { LottieViewBase, autoPlayProperty, keyPathColorsProperty, loopProperty, progressProperty, renderModeProperty, srcProperty, stretchProperty } from "./src/lottie/index.common.js";
|
|
2
|
+
import { clamp } from "./src/lottie/utils.js";
|
|
3
|
+
import { Color, File, Http, Utils, knownFolders, path } from "@nativescript/core";
|
|
4
|
+
//#region src/vendor/ui-lottie/src/lottie/index.android.ts
|
|
5
|
+
/**********************************************************************************
|
|
6
|
+
* (c) 2017, Brad Martin.
|
|
7
|
+
* Licensed under the MIT license.
|
|
8
|
+
*
|
|
9
|
+
* Version 1.0.0 bradwaynemartin@gmail.com
|
|
10
|
+
**********************************************************************************/
|
|
11
|
+
var LottieProperty;
|
|
12
|
+
var LottieKeyPath;
|
|
13
|
+
var LottieValueCallback;
|
|
14
|
+
var LottieCompositionFactory;
|
|
15
|
+
var cache = /* @__PURE__ */ new Map();
|
|
16
|
+
async function loadLottieJSON(iconSrc) {
|
|
17
|
+
if (!cache.has(iconSrc)) {
|
|
18
|
+
const r = await File.fromPath(iconSrc).readText();
|
|
19
|
+
cache.set(iconSrc, r);
|
|
20
|
+
return r;
|
|
21
|
+
}
|
|
22
|
+
return cache.get(iconSrc);
|
|
23
|
+
}
|
|
24
|
+
function loadLottieJSONSync(iconSrc) {
|
|
25
|
+
if (!cache.has(iconSrc)) {
|
|
26
|
+
const r = File.fromPath(iconSrc).readTextSync();
|
|
27
|
+
cache.set(iconSrc, r);
|
|
28
|
+
return r;
|
|
29
|
+
}
|
|
30
|
+
return cache.get(iconSrc);
|
|
31
|
+
}
|
|
32
|
+
var RenderMode = {
|
|
33
|
+
get AUTOMATIC() {
|
|
34
|
+
return com.airbnb.lottie.RenderMode.AUTOMATIC;
|
|
35
|
+
},
|
|
36
|
+
get HARDWARE() {
|
|
37
|
+
return com.airbnb.lottie.RenderMode.HARDWARE;
|
|
38
|
+
},
|
|
39
|
+
get SOFTWARE() {
|
|
40
|
+
return com.airbnb.lottie.RenderMode.SOFTWARE;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
var LottieView = class extends LottieViewBase {
|
|
44
|
+
constructor(..._args) {
|
|
45
|
+
super(..._args);
|
|
46
|
+
this._cancelled = false;
|
|
47
|
+
}
|
|
48
|
+
createNativeView() {
|
|
49
|
+
return new com.nativescript.lottie.LottieAnimationView(this._context);
|
|
50
|
+
}
|
|
51
|
+
get completionBlock() {
|
|
52
|
+
return this._completionBlock;
|
|
53
|
+
}
|
|
54
|
+
set completionBlock(block) {
|
|
55
|
+
this._completionBlock = block;
|
|
56
|
+
if (block) {
|
|
57
|
+
if (!this.animatorListener) {
|
|
58
|
+
const that = new WeakRef(this);
|
|
59
|
+
this.animatorListener = new android.animation.Animator.AnimatorListener({
|
|
60
|
+
onAnimationCancel: (_animator) => {
|
|
61
|
+
const owner = that?.get();
|
|
62
|
+
if (owner) owner._cancelled = true;
|
|
63
|
+
},
|
|
64
|
+
onAnimationEnd: (_animator) => {
|
|
65
|
+
const owner = that?.get();
|
|
66
|
+
if (owner?._completionBlock) owner._completionBlock(!owner._cancelled);
|
|
67
|
+
if (owner) owner._cancelled = false;
|
|
68
|
+
},
|
|
69
|
+
onAnimationRepeat: (_animator) => {},
|
|
70
|
+
onAnimationStart: (_animator) => {}
|
|
71
|
+
});
|
|
72
|
+
if (this.nativeViewProtected) this.nativeViewProtected.addAnimatorListener(this.animatorListener);
|
|
73
|
+
}
|
|
74
|
+
} else if (this.animatorListener) {
|
|
75
|
+
if (this.nativeViewProtected) this.nativeViewProtected.removeAnimatorListener(this.animatorListener);
|
|
76
|
+
this.animatorListener = null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
initNativeView() {
|
|
80
|
+
if (this.animatorListener) this.nativeViewProtected.addAnimatorListener(this.animatorListener);
|
|
81
|
+
if (!this.loadedListener) {
|
|
82
|
+
const that = new WeakRef(this);
|
|
83
|
+
this.loadedListener = new com.airbnb.lottie.LottieOnCompositionLoadedListener({ onCompositionLoaded: (composition) => {
|
|
84
|
+
const owner = that?.get();
|
|
85
|
+
if (owner) setTimeout(() => {
|
|
86
|
+
owner.notify({
|
|
87
|
+
eventName: LottieViewBase.compositionLoadedEvent,
|
|
88
|
+
composition
|
|
89
|
+
});
|
|
90
|
+
if (owner.autoPlay && !owner.isAnimating()) owner.playAnimation();
|
|
91
|
+
}, 0);
|
|
92
|
+
} });
|
|
93
|
+
}
|
|
94
|
+
this.nativeViewProtected.addLottieOnCompositionLoadedListener(this.loadedListener);
|
|
95
|
+
const that = new WeakRef(this);
|
|
96
|
+
this.nativeViewProtected.setFailureListener(new com.airbnb.lottie.LottieListener({ onResult: (result) => {
|
|
97
|
+
const owner = that?.get();
|
|
98
|
+
if (owner) owner.notify({
|
|
99
|
+
eventName: LottieViewBase.loadFailedEvent,
|
|
100
|
+
error: result
|
|
101
|
+
});
|
|
102
|
+
} }));
|
|
103
|
+
}
|
|
104
|
+
disposeNativeView() {
|
|
105
|
+
if (this.animatorListener) this.nativeViewProtected.removeAnimatorListener(this.animatorListener);
|
|
106
|
+
if (this.loadedListener) this.nativeViewProtected.removeLottieOnCompositionLoadedListener(this.loadedListener);
|
|
107
|
+
super.disposeNativeView();
|
|
108
|
+
}
|
|
109
|
+
setColor(value, keyPath) {
|
|
110
|
+
const nativeView = this.nativeViewProtected;
|
|
111
|
+
if (nativeView && value && keyPath && keyPath.length) {
|
|
112
|
+
if (keyPath[keyPath.length - 1].toLowerCase() === "color") {
|
|
113
|
+
keyPath = [...keyPath];
|
|
114
|
+
keyPath.pop();
|
|
115
|
+
if (keyPath.length === 0) return;
|
|
116
|
+
}
|
|
117
|
+
const nativeKeyPath = Array.create(java.lang.String, keyPath.length);
|
|
118
|
+
for (let index = 0; index < keyPath.length; index++) nativeKeyPath[index] = keyPath[index];
|
|
119
|
+
if (!LottieProperty) LottieProperty = com.airbnb.lottie.LottieProperty;
|
|
120
|
+
if (!LottieValueCallback) LottieValueCallback = com.airbnb.lottie.value.LottieValueCallback;
|
|
121
|
+
if (!LottieKeyPath) LottieKeyPath = com.airbnb.lottie.model.KeyPath;
|
|
122
|
+
const color = value instanceof Color ? value : new Color(value);
|
|
123
|
+
const colorFilter = new com.airbnb.lottie.SimpleColorFilter(color.android);
|
|
124
|
+
nativeView.addValueCallback(new LottieKeyPath(nativeKeyPath), LottieProperty.COLOR_FILTER, new LottieValueCallback(colorFilter));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
setOpacity(value, keyPath) {
|
|
128
|
+
if (this.nativeViewProtected && value != null && keyPath && keyPath.length) {
|
|
129
|
+
if (keyPath[keyPath.length - 1].toLowerCase() === "opacity") {
|
|
130
|
+
keyPath = [...keyPath];
|
|
131
|
+
keyPath.pop();
|
|
132
|
+
if (keyPath.length === 0) return;
|
|
133
|
+
}
|
|
134
|
+
const nativeKeyPath = Array.create(java.lang.String, keyPath.length);
|
|
135
|
+
keyPath.forEach((key, index) => {
|
|
136
|
+
nativeKeyPath[index] = new java.lang.String(key);
|
|
137
|
+
});
|
|
138
|
+
value = clamp(value);
|
|
139
|
+
if (!LottieProperty) LottieProperty = com.airbnb.lottie.LottieProperty;
|
|
140
|
+
if (!LottieValueCallback) LottieValueCallback = com.airbnb.lottie.value.LottieValueCallback;
|
|
141
|
+
if (!LottieKeyPath) LottieKeyPath = com.airbnb.lottie.model.KeyPath;
|
|
142
|
+
this.nativeViewProtected.addValueCallback(new LottieKeyPath(nativeKeyPath), LottieProperty.OPACITY, new LottieValueCallback(new java.lang.Integer(value * 255)));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
playAnimation() {
|
|
146
|
+
if (this.nativeViewProtected) {
|
|
147
|
+
this.nativeViewProtected.setMinAndMaxProgress(0, 1);
|
|
148
|
+
this.nativeViewProtected.playAnimation();
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
playAnimationFromProgressToProgress(startProgress, endProgress) {
|
|
152
|
+
if (this.nativeViewProtected) {
|
|
153
|
+
startProgress = startProgress ? clamp(startProgress) : 0;
|
|
154
|
+
endProgress = endProgress ? clamp(endProgress) : 1;
|
|
155
|
+
this.nativeViewProtected.setMinAndMaxProgress(startProgress, endProgress);
|
|
156
|
+
this.nativeViewProtected.playAnimation();
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
isAnimating() {
|
|
160
|
+
return this.nativeViewProtected ? this.nativeViewProtected.isAnimating() : false;
|
|
161
|
+
}
|
|
162
|
+
get speed() {
|
|
163
|
+
return this.nativeViewProtected ? this.nativeViewProtected.getSpeed() : void 0;
|
|
164
|
+
}
|
|
165
|
+
set speed(value) {
|
|
166
|
+
if (this.nativeViewProtected && value) this.nativeViewProtected.setSpeed(value);
|
|
167
|
+
}
|
|
168
|
+
get duration() {
|
|
169
|
+
return this.nativeViewProtected ? this.nativeViewProtected.getDuration() : void 0;
|
|
170
|
+
}
|
|
171
|
+
cancelAnimation() {
|
|
172
|
+
if (this.nativeViewProtected) this.nativeViewProtected.cancelAnimation();
|
|
173
|
+
}
|
|
174
|
+
pauseAnimation() {
|
|
175
|
+
if (this.nativeViewProtected) this.nativeViewProtected.pauseAnimation();
|
|
176
|
+
}
|
|
177
|
+
resumeAnimation() {
|
|
178
|
+
if (this.nativeViewProtected) this.nativeViewProtected.resumeAnimation();
|
|
179
|
+
}
|
|
180
|
+
[srcProperty.setNative](src) {
|
|
181
|
+
try {
|
|
182
|
+
if (!LottieCompositionFactory) LottieCompositionFactory = com.airbnb.lottie.LottieCompositionFactory;
|
|
183
|
+
const view = this.nativeViewProtected;
|
|
184
|
+
let result;
|
|
185
|
+
if (!src) {} else if (src[0] === "{") {
|
|
186
|
+
if (this.async) view.setAnimationFromJson(src, null);
|
|
187
|
+
else result = LottieCompositionFactory.fromJsonStringSync(src, null);
|
|
188
|
+
} else if (/^https?:/i.test(src)) {
|
|
189
|
+
const match = /\.(zip|lottie|json)(?=[?#]|$)/i.exec(src);
|
|
190
|
+
const dest = path.join(knownFolders.temp().path, `lottie-${Date.now()}${match ? match[0].toLowerCase() : ".json"}`);
|
|
191
|
+
Http.getFile(src, dest).then(() => {
|
|
192
|
+
this.src = dest;
|
|
193
|
+
}).catch((error) => {
|
|
194
|
+
console.error(error);
|
|
195
|
+
this.notify({
|
|
196
|
+
eventName: "loadFailed",
|
|
197
|
+
error
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
} else if (src.startsWith(Utils.RESOURCE_PREFIX)) {
|
|
201
|
+
const resName = src.replace(Utils.RESOURCE_PREFIX, "");
|
|
202
|
+
if (this.async) view.setAnimation(resName);
|
|
203
|
+
else result = com.airbnb.lottie.LottieCompositionFactory.fromAssetSync(this._context, resName);
|
|
204
|
+
} else {
|
|
205
|
+
if (!/.(json|zip|lottie)$/.test(src)) src += ".json";
|
|
206
|
+
if (src[0] === "~") {
|
|
207
|
+
if (this.async) view.setAnimation("app/" + src.substring(2));
|
|
208
|
+
else result = com.airbnb.lottie.LottieCompositionFactory.fromAssetSync(this._context, "app/" + src.substring(2));
|
|
209
|
+
} else if (!src.startsWith("file:/") && src[0] !== "/") {
|
|
210
|
+
if (this.async) view.setAnimation("app/" + src);
|
|
211
|
+
else result = com.airbnb.lottie.LottieCompositionFactory.fromAssetSync(this._context, src);
|
|
212
|
+
} else {
|
|
213
|
+
const filePath = src.startsWith("file:") ? src.substring(5) : src;
|
|
214
|
+
if (/\.(zip|lottie)$/i.test(filePath)) {
|
|
215
|
+
const stream = new java.util.zip.ZipInputStream(new java.io.FileInputStream(filePath));
|
|
216
|
+
if (this.async) {
|
|
217
|
+
const owner = new WeakRef(this);
|
|
218
|
+
com.airbnb.lottie.LottieCompositionFactory.fromZipStream(stream, null).addListener(new com.airbnb.lottie.LottieListener({ onResult: (composition) => {
|
|
219
|
+
const view = owner.get()?.nativeViewProtected;
|
|
220
|
+
if (view) view.setComposition(composition);
|
|
221
|
+
} })).addFailureListener(new com.airbnb.lottie.LottieListener({ onResult: (error) => console.error(error) }));
|
|
222
|
+
} else result = com.airbnb.lottie.LottieCompositionFactory.fromZipStreamSync(stream, null);
|
|
223
|
+
} else if (this.async) loadLottieJSON(src).then((result) => {
|
|
224
|
+
if (this.nativeViewProtected) this.nativeViewProtected.setAnimationFromJson(result, null);
|
|
225
|
+
});
|
|
226
|
+
else result = LottieCompositionFactory.fromJsonStringSync(loadLottieJSONSync(src), null);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
if (result) {
|
|
230
|
+
if (result.getException()) {
|
|
231
|
+
console.error(result.getException());
|
|
232
|
+
this.notify({
|
|
233
|
+
eventName: LottieViewBase.loadFailedEvent,
|
|
234
|
+
error: result.getException()
|
|
235
|
+
});
|
|
236
|
+
} else view.setComposition(result.getValue());
|
|
237
|
+
}
|
|
238
|
+
if (this.autoPlay) this.playAnimation();
|
|
239
|
+
} catch (error) {
|
|
240
|
+
console.error(error);
|
|
241
|
+
this.notify({
|
|
242
|
+
eventName: LottieViewBase.loadFailedEvent,
|
|
243
|
+
error
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
[loopProperty.setNative](loop) {
|
|
248
|
+
this.nativeViewProtected.setRepeatCount(loop ? -1 : 0);
|
|
249
|
+
}
|
|
250
|
+
[progressProperty.setNative](value) {
|
|
251
|
+
this.nativeViewProtected.setProgress(value);
|
|
252
|
+
}
|
|
253
|
+
[renderModeProperty.setNative](renderMode) {
|
|
254
|
+
this.nativeViewProtected.setRenderMode(renderMode);
|
|
255
|
+
}
|
|
256
|
+
[keyPathColorsProperty.setNative](value) {
|
|
257
|
+
Object.keys(value).forEach((k) => this.setColor(value[k], k.split("|")));
|
|
258
|
+
}
|
|
259
|
+
[autoPlayProperty.setNative](autoPlay) {
|
|
260
|
+
if (autoPlay) {
|
|
261
|
+
if (!this.isAnimating()) this.playAnimation();
|
|
262
|
+
} else {
|
|
263
|
+
this.cancelAnimation();
|
|
264
|
+
if (this.progress) this.nativeViewProtected.setProgress(this.progress);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
[stretchProperty.getDefault]() {
|
|
268
|
+
return "aspectFit";
|
|
269
|
+
}
|
|
270
|
+
[stretchProperty.setNative](value) {
|
|
271
|
+
switch (value) {
|
|
272
|
+
case "aspectFit":
|
|
273
|
+
this.nativeViewProtected.setScaleType(android.widget.ImageView.ScaleType.FIT_CENTER);
|
|
274
|
+
break;
|
|
275
|
+
case "aspectFill":
|
|
276
|
+
this.nativeViewProtected.setScaleType(android.widget.ImageView.ScaleType.CENTER_CROP);
|
|
277
|
+
break;
|
|
278
|
+
case "fill":
|
|
279
|
+
this.nativeViewProtected.setScaleType(android.widget.ImageView.ScaleType.FIT_XY);
|
|
280
|
+
break;
|
|
281
|
+
default: this.nativeViewProtected.setScaleType(android.widget.ImageView.ScaleType.MATRIX);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
//#endregion
|
|
286
|
+
export { LottieView, RenderMode };
|