@react-native-ohos/lottie-react-native 7.2.3-rc.1

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.
Files changed (62) hide show
  1. package/LICENSE +201 -0
  2. package/README.OpenSource +11 -0
  3. package/README.md +13 -0
  4. package/harmony/lottie/BuildProfile.ets +21 -0
  5. package/harmony/lottie/build-profile.json5 +8 -0
  6. package/harmony/lottie/hvigorfile.ts +5 -0
  7. package/harmony/lottie/index.ets +5 -0
  8. package/harmony/lottie/oh-package.json5 +14 -0
  9. package/harmony/lottie/src/main/cpp/CMakeLists.txt +9 -0
  10. package/harmony/lottie/src/main/cpp/LottieAnimationViewPackage.h +13 -0
  11. package/harmony/lottie/src/main/cpp/generated/RNOH/generated/BaseLottieReactNativePackage.h +68 -0
  12. package/harmony/lottie/src/main/cpp/generated/RNOH/generated/components/LottieAnimationViewJSIBinder.h +43 -0
  13. package/harmony/lottie/src/main/cpp/generated/react/renderer/components/lottie_react_native/ComponentDescriptors.h +22 -0
  14. package/harmony/lottie/src/main/cpp/generated/react/renderer/components/lottie_react_native/EventEmitters.cpp +44 -0
  15. package/harmony/lottie/src/main/cpp/generated/react/renderer/components/lottie_react_native/EventEmitters.h +39 -0
  16. package/harmony/lottie/src/main/cpp/generated/react/renderer/components/lottie_react_native/Props.cpp +41 -0
  17. package/harmony/lottie/src/main/cpp/generated/react/renderer/components/lottie_react_native/Props.h +42 -0
  18. package/harmony/lottie/src/main/cpp/generated/react/renderer/components/lottie_react_native/ShadowNodes.cpp +19 -0
  19. package/harmony/lottie/src/main/cpp/generated/react/renderer/components/lottie_react_native/ShadowNodes.h +34 -0
  20. package/harmony/lottie/src/main/cpp/generated/react/renderer/components/lottie_react_native/States.cpp +18 -0
  21. package/harmony/lottie/src/main/cpp/generated/react/renderer/components/lottie_react_native/States.h +36 -0
  22. package/harmony/lottie/src/main/ets/LottieAnimationTools.ets +21 -0
  23. package/harmony/lottie/src/main/ets/LottieAnimationView.ets +393 -0
  24. package/harmony/lottie/src/main/ets/LottieAnimationViewPackage.ts +17 -0
  25. package/harmony/lottie/src/main/ets/LottieCompositionCache.ets +30 -0
  26. package/harmony/lottie/src/main/ets/common/Animation.ts +43 -0
  27. package/harmony/lottie/src/main/ets/common/AnimationType.ets +50 -0
  28. package/harmony/lottie/src/main/ets/common/TextUtils.ets +18 -0
  29. package/harmony/lottie/src/main/ets/generated/components/LottieAnimationView.ts +181 -0
  30. package/harmony/lottie/src/main/ets/generated/components/ts.ts +5 -0
  31. package/harmony/lottie/src/main/ets/generated/index.ets +5 -0
  32. package/harmony/lottie/src/main/ets/generated/ts.ts +6 -0
  33. package/harmony/lottie/src/main/ets/generated/turboModules/ts.ts +5 -0
  34. package/harmony/lottie/src/main/module.json5 +9 -0
  35. package/harmony/lottie/src/main/resources/base/element/string.json +8 -0
  36. package/harmony/lottie/src/main/resources/base/media/icon.png +0 -0
  37. package/harmony/lottie/src/main/resources/en_US/element/string.json +8 -0
  38. package/harmony/lottie/src/main/resources/zh_CN/element/string.json +8 -0
  39. package/harmony/lottie/ts.ts +5 -0
  40. package/harmony/lottie.har +0 -0
  41. package/lib/commonjs/LottieAnimationViewNativeComponent.js +18 -0
  42. package/lib/commonjs/LottieAnimationViewNativeComponent.js.map +1 -0
  43. package/lib/commonjs/codegenUtils.js +2 -0
  44. package/lib/commonjs/codegenUtils.js.map +1 -0
  45. package/lib/commonjs/index.js +25 -0
  46. package/lib/commonjs/index.js.map +1 -0
  47. package/lib/module/LottieAnimationViewNativeComponent.js +11 -0
  48. package/lib/module/LottieAnimationViewNativeComponent.js.map +1 -0
  49. package/lib/module/codegenUtils.js +2 -0
  50. package/lib/module/codegenUtils.js.map +1 -0
  51. package/lib/module/index.js +8 -0
  52. package/lib/module/index.js.map +1 -0
  53. package/lib/typescript/LottieAnimationViewNativeComponent.d.ts +44 -0
  54. package/lib/typescript/LottieAnimationViewNativeComponent.d.ts.map +1 -0
  55. package/lib/typescript/codegenUtils.d.ts +3 -0
  56. package/lib/typescript/codegenUtils.d.ts.map +1 -0
  57. package/lib/typescript/index.d.ts +4 -0
  58. package/lib/typescript/index.d.ts.map +1 -0
  59. package/package.json +131 -0
  60. package/src/LottieAnimationViewNativeComponent.ts +78 -0
  61. package/src/codegenUtils.ts +9 -0
  62. package/src/index.tsx +7 -0
@@ -0,0 +1,34 @@
1
+
2
+ /**
3
+ * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
4
+ *
5
+ * Do not edit this file as changes may cause incorrect behavior and will be lost
6
+ * once the code is regenerated.
7
+ *
8
+ * @generated by codegen project: GenerateShadowNodeH.js
9
+ */
10
+
11
+ #pragma once
12
+
13
+ #include <react/renderer/components/lottie_react_native/EventEmitters.h>
14
+ #include <react/renderer/components/lottie_react_native/Props.h>
15
+ #include <react/renderer/components/lottie_react_native/States.h>
16
+ #include <react/renderer/components/view/ConcreteViewShadowNode.h>
17
+ #include <jsi/jsi.h>
18
+
19
+ namespace facebook {
20
+ namespace react {
21
+
22
+ JSI_EXPORT extern const char LottieAnimationViewComponentName[];
23
+
24
+ /*
25
+ * `ShadowNode` for <LottieAnimationView> component.
26
+ */
27
+ using LottieAnimationViewShadowNode = ConcreteViewShadowNode<
28
+ LottieAnimationViewComponentName,
29
+ LottieAnimationViewProps,
30
+ LottieAnimationViewEventEmitter,
31
+ LottieAnimationViewState>;
32
+
33
+ } // namespace react
34
+ } // namespace facebook
@@ -0,0 +1,18 @@
1
+
2
+ /**
3
+ * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
4
+ *
5
+ * Do not edit this file as changes may cause incorrect behavior and will be lost
6
+ * once the code is regenerated.
7
+ *
8
+ * @generated by codegen project: GenerateStateCpp.js
9
+ */
10
+ #include <react/renderer/components/lottie_react_native/States.h>
11
+
12
+ namespace facebook {
13
+ namespace react {
14
+
15
+
16
+
17
+ } // namespace react
18
+ } // namespace facebook
@@ -0,0 +1,36 @@
1
+ /**
2
+ * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
3
+ *
4
+ * Do not edit this file as changes may cause incorrect behavior and will be lost
5
+ * once the code is regenerated.
6
+ *
7
+ * @generated by codegen project: GenerateStateH.js
8
+ */
9
+ #pragma once
10
+
11
+ #ifdef ANDROID
12
+ #include <folly/dynamic.h>
13
+ #include <react/renderer/mapbuffer/MapBuffer.h>
14
+ #include <react/renderer/mapbuffer/MapBufferBuilder.h>
15
+ #endif
16
+
17
+ namespace facebook {
18
+ namespace react {
19
+
20
+ class LottieAnimationViewState {
21
+ public:
22
+ LottieAnimationViewState() = default;
23
+
24
+ #ifdef ANDROID
25
+ LottieAnimationViewState(LottieAnimationViewState const &previousState, folly::dynamic data){};
26
+ folly::dynamic getDynamic() const {
27
+ return {};
28
+ };
29
+ MapBuffer getMapBuffer() const {
30
+ return MapBufferBuilder::EMPTY();
31
+ };
32
+ #endif
33
+ };
34
+
35
+ } // namespace react
36
+ } // namespace facebook
@@ -0,0 +1,21 @@
1
+ // Copyright (c) 2025 Huawei Device Co., Ltd. All rights reserved
2
+ // Use of this source code is governed by a Apache-2.0 license that can be
3
+ // found in the LICENSE file.
4
+
5
+ import { AnimationObject, AnimationAssets } from './common/Animation'
6
+ import { isEmpty } from './common/TextUtils'
7
+
8
+ export function convertImageFolder(jsonData: AnimationObject, imagesFolder: string): AnimationObject {
9
+ let assets: AnimationAssets[] = jsonData.assets
10
+ if (assets != undefined && assets.length > 0 && !isEmpty(imagesFolder)) {
11
+ if (imagesFolder.charAt(imagesFolder.length - 1) != '/') {
12
+ imagesFolder = imagesFolder + '/'
13
+ }
14
+ let assetsTemp: AnimationAssets[] = assets.map((obj: AnimationAssets) => {
15
+ obj.u = imagesFolder
16
+ return obj
17
+ })
18
+ jsonData.assets = assetsTemp
19
+ }
20
+ return jsonData
21
+ }
@@ -0,0 +1,393 @@
1
+ // Copyright (c) 2025 Huawei Device Co., Ltd. All rights reserved
2
+ // Use of this source code is governed by a Apache-2.0 license that can be
3
+ // found in the LICENSE file.
4
+
5
+ import { RNOHContext, RNViewBase } from '@rnoh/react-native-openharmony';
6
+ import lottie from '@ohos/lottie';
7
+ import { AnimationItem } from '@ohos/lottie';
8
+ import http from '@ohos.net.http';
9
+ import { colorFiltersItem, LOTTLE_STRING } from './common/AnimationType';
10
+ import { AnimationObject, layersItem } from './common/Animation';
11
+ import { LottieCompositionCache } from './LottieCompositionCache';
12
+ import { convertImageFolder } from './LottieAnimationTools';
13
+ import { getHashCode } from './common/TextUtils';
14
+ import { RNOHLogger } from "@rnoh/react-native-openharmony/ts";
15
+ import { RNC } from './generated';
16
+ /**
17
+ * @deprecated Use LottieAnimationView.NAME instead
18
+ */
19
+ export const LOTTIE_TYPE: string = RNC.LottieAnimationView.NAME
20
+
21
+ @Component
22
+ export struct LottieAnimationView {
23
+ public static readonly NAME = RNC.LottieAnimationView.NAME
24
+ ctx!: RNOHContext;
25
+ tag: number = 0;
26
+ private logger!: RNOHLogger
27
+ @State descriptorWrapper: RNC.LottieAnimationView.DescriptorWrapper = {} as RNC.LottieAnimationView.DescriptorWrapper;
28
+ private unregisterDescriptorChangesListener?: () => void = undefined;
29
+ @State @Watch('onStateChanged') progress: number = 0;
30
+ @State @Watch('onStateChanged') speed: number = 1;
31
+ @State @Watch('onStateChanged') loop: boolean = true;
32
+ @State @Watch('onStateChanged') autoPlay: boolean = false;
33
+ @State @Watch('onStateChanged') cacheComposition: boolean = true;
34
+ private jsonData: AnimationObject | null = {} as AnimationObject;
35
+ private jsonDataHashCode: string = '';
36
+ private cleanupCommandCallback?: () => void = undefined;
37
+ private renderingSettings: RenderingContextSettings = new RenderingContextSettings(true);
38
+ private canvasRenderingContext: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.renderingSettings);
39
+ private animateItem: AnimationItem | null = null;
40
+ private lottieCache = LottieCompositionCache.getInstance();
41
+ private animateKey: string | null = null;
42
+ private eventEmitter: RNC.LottieAnimationView.EventEmitter | undefined = undefined
43
+
44
+ aboutToAppear() {
45
+ // 创建EventEmitter实例,用于处理事件的订阅和触发
46
+ this.eventEmitter = new RNC.LottieAnimationView.EventEmitter(this.ctx.rnInstance, this.tag)
47
+ this.logger = this.ctx!.logger.clone(RNC.LottieAnimationView.NAME)
48
+ this.onDescriptorWrapperChange(this.ctx.descriptorRegistry.findDescriptorWrapperByTag<RNC.LottieAnimationView.DescriptorWrapper>(this.tag)!)
49
+ this.commandCallback();
50
+ this.subscribeToDescriptorChanges();
51
+ lottie.bindContext2dToCoordinator(this.canvasRenderingContext)
52
+ this.logger.info(`testlottie:${JSON.stringify(this.descriptorWrapper.props)}`)
53
+ }
54
+
55
+ private onDescriptorWrapperChange(descriptorWrapper: RNC.LottieAnimationView.DescriptorWrapper) {
56
+ this.descriptorWrapper = descriptorWrapper
57
+ }
58
+
59
+ aboutToDisappear() {
60
+ this.cleanupCommandCallback?.();
61
+ this.unregisterDescriptorChangesListener?.();
62
+ this.destroyAnimation();
63
+ if (this.animateKey) {
64
+ lottie.destroy(this.animateKey);
65
+ }
66
+ this.animateKey = null;
67
+ lottie.unbindContext2dFromCoordinator(this.canvasRenderingContext)
68
+ }
69
+
70
+ subscribeToDescriptorChanges(): void {
71
+ this.unregisterDescriptorChangesListener = this.ctx.descriptorRegistry.subscribeToDescriptorChanges(this.tag,
72
+ (newDescriptor: object) => {
73
+ this.descriptorWrapper = (newDescriptor as RNC.LottieAnimationView.DescriptorWrapper);
74
+ this.onDescriptorChanged(true);
75
+ }
76
+ )
77
+ }
78
+
79
+ onDescriptorChanged(change?: boolean): void {
80
+ if (this.descriptorWrapper.props) {
81
+ this.handleColorFilters();
82
+ this.updateWatchData();
83
+ change && this.parseSourceURL();
84
+ }
85
+ }
86
+
87
+ onStateChanged(propName: string): void {
88
+ if (this.animateItem == null) {
89
+ return;
90
+ }
91
+ switch (propName) {
92
+ case LOTTLE_STRING.progress:
93
+ this.setProgress();
94
+ break;
95
+ case LOTTLE_STRING.speed:
96
+ this.setSpeed();
97
+ break;
98
+ case LOTTLE_STRING.loop: {
99
+ this.animateItem.loop = this.loop;
100
+ break;
101
+ }
102
+ case LOTTLE_STRING.autoPlay:
103
+ this.setAutoPlay();
104
+ break;
105
+ default:
106
+ break;
107
+ }
108
+ }
109
+
110
+ onAnimationFinish(isCancelled: boolean): void {
111
+ this.eventEmitter!.emit("animationFinish", {isCancelled: isCancelled});
112
+ }
113
+
114
+ onAnimationCancel(): void {
115
+ this.onAnimationFinish(true);
116
+ }
117
+
118
+ onAnimationEnd(): void {
119
+ this.onAnimationFinish(false);
120
+ }
121
+
122
+ cacheProcessing(data: string, isURL?: boolean): void {
123
+ const hashCode = getHashCode(data);
124
+ if (hashCode === this.jsonDataHashCode) {
125
+ return;
126
+ }
127
+ if (this.descriptorWrapper.props.cacheComposition) {
128
+ const tempJsonObj = this.getCacheData(hashCode);
129
+ if (tempJsonObj) {
130
+ this.jsonData = tempJsonObj;
131
+ this.jsonDataHashCode = hashCode;
132
+ this.initAnimation();
133
+ return;
134
+ }
135
+ }
136
+ if (isURL) {
137
+ this.request(data, hashCode);
138
+ } else {
139
+ this.updateJsonData(data, hashCode);
140
+ }
141
+ }
142
+
143
+ parseSourceURL(): void {
144
+ if (!this.descriptorWrapper?.props) {
145
+ return;
146
+ }
147
+ if (this.descriptorWrapper.props.sourceURL &&
148
+ this.descriptorWrapper.props.sourceURL.startsWith(LOTTLE_STRING.http)) {
149
+ this.cacheProcessing(this.descriptorWrapper.props.sourceURL, true);
150
+ } else {
151
+ this.descriptorWrapper.props.sourceJson && this.cacheProcessing(this.descriptorWrapper.props.sourceJson);
152
+ }
153
+ }
154
+
155
+ request(url: string, hashCode?: string): void {
156
+ this.logger.debug('httpRequest.request url:', url);
157
+ const httpRequest = http.createHttp();
158
+ httpRequest.request(url, { header: { [LOTTLE_STRING.contentType]: LOTTLE_STRING.json } }, (err, data) => {
159
+ if (err == undefined && data != undefined) {
160
+ this.logger.debug('httpRequest.request success:', JSON.stringify(data));
161
+ const result: Object = data.result;
162
+ if (result) {
163
+ this.updateJsonData(result as string, hashCode);
164
+ }
165
+ } else {
166
+ this.logger.error('httpRequest.request error:', `errorCode: ${err?.code}`);
167
+ }
168
+ })
169
+ }
170
+
171
+ updateWatchData(): void {
172
+ this.progress = this.descriptorWrapper.props.progress;
173
+ this.speed = this.descriptorWrapper.props.speed;
174
+ this.loop = Boolean(this.descriptorWrapper.props.loop);
175
+ this.autoPlay = Boolean(this.descriptorWrapper.props.autoPlay);
176
+ this.cacheComposition = Boolean(this.descriptorWrapper.props.cacheComposition);
177
+ }
178
+
179
+ updateJsonData(data: string, hashCode?: string): void {
180
+ try {
181
+ this.jsonData =
182
+ convertImageFolder(JSON.parse(data) as AnimationObject,
183
+ this.descriptorWrapper.props.imageAssetsFolder as string);
184
+ this.initAnimation();
185
+ this.setCacheData(this.jsonData as AnimationObject, hashCode);
186
+ } catch (e) {
187
+ this.logger.error('updateJsonData,source parse error');
188
+ this.jsonData = null;
189
+ }
190
+ }
191
+
192
+ setCacheData(jsonObj: AnimationObject, key?: string): void {
193
+ if (key) {
194
+ this.lottieCache.set(key, jsonObj);
195
+ this.jsonDataHashCode = key;
196
+ }
197
+ }
198
+
199
+ getCacheData(key: string): AnimationObject | null {
200
+ return this.lottieCache.get(key);
201
+ }
202
+
203
+ initAnimation(): void {
204
+ if (this.jsonData == null) {
205
+ return;
206
+ }
207
+ this.loadAnimation();
208
+ this.setSpeed();
209
+ this.addEventFrameListener();
210
+ }
211
+
212
+ destroyAnimation(): void {
213
+ if (this.animateItem == null) {
214
+ return;
215
+ }
216
+ if (this.animateItem.isPaused === false) {
217
+ this.onAnimationEnd();
218
+ }
219
+ lottie.destroy(this.animateKey);
220
+ this.animateItem = null;
221
+ }
222
+
223
+ loadAnimation(): void {
224
+ this.destroyAnimation();
225
+ this.animateKey = `${this.tag}${new Date().getTime()}`;
226
+ this.animateItem = lottie.loadAnimation({
227
+ container: this.canvasRenderingContext,
228
+ renderer: LOTTLE_STRING.canvas,
229
+ name: this.animateKey,
230
+ loop: Boolean(this.descriptorWrapper.props.loop),
231
+ autoplay: Boolean(this.descriptorWrapper.props.autoPlay),
232
+ animationData: this.jsonData
233
+ });
234
+ this.animateItem?.addEventListener(LOTTLE_STRING.DOMLoaded, () => {
235
+ try{
236
+ let upperResizeMode =
237
+ this.descriptorWrapper.props?.resizeMode?.replace(this.descriptorWrapper.props.resizeMode[0],
238
+ this.descriptorWrapper.props.resizeMode[0].toUpperCase())
239
+ this.eventEmitter!.emit("animationLoaded", {});
240
+ this.animateItem?.setContentMode(upperResizeMode);
241
+ this.onDescriptorChanged();
242
+ }catch(e) {
243
+ this.logger.error('DOMLoaded catch error:', e);
244
+ }
245
+ })
246
+ this.animateItem?.addEventListener(LOTTLE_STRING.data_failed, () => {
247
+ this.eventEmitter!.emit("animationFailure", {error: 'data_failed'});
248
+ })
249
+ }
250
+
251
+ handleColorFilters(): void {
252
+ const layersData: Array<layersItem> = this.jsonData?.layers ?? [];
253
+ const colorFiltersData: Array<colorFiltersItem> =
254
+ (this.descriptorWrapper.props.colorFilters ?? []) as Array<colorFiltersItem>;
255
+ for (const item of colorFiltersData) {
256
+ const index: number = layersData.findIndex((layersItem: layersItem) => layersItem?.nm === item?.keypath);
257
+ const color: Array<number> = this.getColorByColorFilters(item);
258
+ const isIndex: boolean = index !== (-1);
259
+ const isColor: boolean = color.length === 3;
260
+ if (isIndex && isColor) {
261
+ this.animateItem?.changeColor(color, index + 1);
262
+ this.logger.debug('colorFilters success:', item?.keypath);
263
+ } else {
264
+ this.logger.error('colorFilters fail:not find keyPath', item?.keypath);
265
+ }
266
+ }
267
+ }
268
+
269
+ getColorByColorFilters(colorFiltersItem: colorFiltersItem): Array<number> {
270
+ const color: string = colorFiltersItem?.color;
271
+ if (color) {
272
+ const processColor: number = Number(color);
273
+ const r: number = (processColor >> 16) & 0xff;
274
+ const g: number = (processColor >> 8) & 0xff;
275
+ const b: number = processColor & 0xff;
276
+ this.logger.debug(`getColorByColorFilters, r=${r}, g=${g}, b=${b}`);
277
+ return [r, g, b];
278
+ }
279
+ this.logger.error('colorFilters fail:not find color', colorFiltersItem?.keypath);
280
+ return [];
281
+ }
282
+
283
+ setProgress(): void {
284
+ const frame = this.getAnimateFrame();
285
+ this.animateItem?.goToAndStop(frame, true);
286
+ }
287
+
288
+ setSpeed(): void {
289
+ this.animateItem?.setSpeed(this.descriptorWrapper.props.speed);
290
+ }
291
+
292
+ setAutoPlay(): void {
293
+ this.animateItem?.goToAndPlay(this.getAnimateFrame(), true);
294
+ }
295
+
296
+ getAnimateFrame(): number {
297
+ const firstFrame: number = this.animateItem?.firstFrame ?? 0;
298
+ const totalFrames: number = this.animateItem?.totalFrames ?? 0;
299
+ return Math.ceil(firstFrame + this.descriptorWrapper.props.progress * totalFrames);
300
+ }
301
+
302
+ addEventFrameListener(): void {
303
+ this.completeEvent();
304
+ }
305
+
306
+ completeEvent(): void {
307
+ //动画播放结束且不再播放动画触发
308
+ this.animateItem?.addEventListener(LOTTLE_STRING.complete, () => {
309
+ this.onAnimationFinish(false);
310
+ })
311
+ }
312
+
313
+ commandCallback(): void {
314
+ this.cleanupCommandCallback = this.ctx.componentCommandReceiver.registerCommandCallback(
315
+ this.tag,
316
+ (command: string, args: object) => {
317
+ if (this.animateItem == null) {
318
+ return;
319
+ }
320
+ switch (command) {
321
+ case LOTTLE_STRING.play:
322
+ this.play(args as number[]);
323
+ break;
324
+ case LOTTLE_STRING.reset:
325
+ this.reset();
326
+ break;
327
+ case LOTTLE_STRING.pause:
328
+ this.pause();
329
+ break;
330
+ case LOTTLE_STRING.resume:
331
+ this.resume();
332
+ break;
333
+ default:
334
+ this.logger.warn('not find command');
335
+ break;
336
+ }
337
+ })
338
+ }
339
+
340
+ play(args: number[]): void {
341
+ const startFrame = args[0];
342
+ const endFrame = args[1];
343
+ this.animateItem?.stop();
344
+ if (this.progress !== 0) {
345
+ this.progress = 0;
346
+ this.animateItem?.goToAndPlay(this.getAnimateFrame(), true);
347
+ return;
348
+ }
349
+ if (args.length > 1 && startFrame != -1 && endFrame != -1) {
350
+ if (startFrame > endFrame) {
351
+ this.animateItem?.setSegment(endFrame, startFrame);
352
+ if (this.descriptorWrapper.props.speed > 0) {
353
+ this.animateItem?.setDirection(-1);
354
+ }
355
+ } else {
356
+ this.animateItem?.setSegment(startFrame, endFrame);
357
+ if (this.descriptorWrapper.props.speed < 0) {
358
+ this.animateItem?.setDirection(-1);
359
+ }
360
+ }
361
+ }
362
+ this.animateItem?.play();
363
+ }
364
+
365
+ reset(): void {
366
+ this.animateItem?.stop();
367
+ this.onAnimationEnd();
368
+ }
369
+
370
+ pause(): void {
371
+ this.animateItem?.pause();
372
+ }
373
+
374
+ resume(): void {
375
+ if (this.animateItem?.isPaused) {
376
+ this.animateItem?.togglePause();
377
+ }
378
+ }
379
+
380
+ resize(): void {
381
+ this.animateItem?.resize();
382
+ }
383
+
384
+ build() {
385
+ RNViewBase({ ctx: this.ctx, tag: this.tag }) {
386
+ Canvas(this.canvasRenderingContext)
387
+ .width('100%')
388
+ .height('100%')
389
+ .onReady(() => this.parseSourceURL())
390
+ .onAreaChange(() => this.resize())
391
+ }
392
+ }
393
+ }
@@ -0,0 +1,17 @@
1
+ // Copyright (c) 2025 Huawei Device Co., Ltd. All rights reserved
2
+ // Use of this source code is governed by a Apache-2.0 license that can be
3
+ // found in the LICENSE file.
4
+
5
+ import { RNPackage } from '@rnoh/react-native-openharmony/ts';
6
+ import type {DescriptorWrapperFactoryByDescriptorTypeCtx, DescriptorWrapperFactoryByDescriptorType} from '@rnoh/react-native-openharmony/ts';
7
+ import { RNC } from './generated/ts';
8
+
9
+ export class LottieAnimationViewPackage extends RNPackage {
10
+ createDescriptorWrapperFactoryByDescriptorType(ctx:
11
+ DescriptorWrapperFactoryByDescriptorTypeCtx):
12
+ DescriptorWrapperFactoryByDescriptorType {
13
+ return {
14
+ [RNC.LottieAnimationView.NAME]: (ctx) => new RNC.LottieAnimationView.DescriptorWrapper(ctx.descriptor)
15
+ }
16
+ }
17
+ }
@@ -0,0 +1,30 @@
1
+ // Copyright (c) 2025 Huawei Device Co., Ltd. All rights reserved
2
+ // Use of this source code is governed by a Apache-2.0 license that can be
3
+ // found in the LICENSE file.
4
+
5
+ import HashMap from '@ohos.util.HashMap'
6
+ import { AnimationObject } from './common/Animation'
7
+
8
+ export class LottieCompositionCache {
9
+ private static readonly sInstance: LottieCompositionCache = new LottieCompositionCache()
10
+ private cache: HashMap<String, AnimationObject> = new HashMap()
11
+
12
+ public static getInstance(): LottieCompositionCache {
13
+ return LottieCompositionCache.sInstance
14
+ }
15
+
16
+ get(cacheKey: string): AnimationObject | null {
17
+ return cacheKey ? this.cache.get(cacheKey) : null
18
+ }
19
+
20
+ set(cacheKey: string, composition: AnimationObject): void {
21
+ if (cacheKey.length === 0) {
22
+ return
23
+ }
24
+ this.cache.set(cacheKey, composition)
25
+ }
26
+
27
+ clear(): void {
28
+ this.cache.clear()
29
+ }
30
+ }
@@ -0,0 +1,43 @@
1
+ // Copyright (c) 2025 Huawei Device Co., Ltd. All rights reserved
2
+ // Use of this source code is governed by a Apache-2.0 license that can be
3
+ // found in the LICENSE file.
4
+
5
+ export interface layersItem {
6
+ "ddd"?: number;
7
+ "ind"?: number;
8
+ "ty"?: number;
9
+ "nm"?: string;
10
+ "sr"?: number;
11
+ "ks": object;
12
+ "ao"?: number;
13
+ "shapes": Array<{ [key: string]: string | number }>
14
+ "ip"?: number;
15
+ "op"?: number;
16
+ "st"?: number;
17
+ "bm"?: number;
18
+
19
+ [key: string]: string | number | object | [];
20
+ }
21
+
22
+ export type AnimationObject = {
23
+ v: string
24
+ fr: number
25
+ ip: number
26
+ op: number
27
+ w: number
28
+ h: number
29
+ nm?: string
30
+ ddd?: number
31
+ assets: AnimationAssets[]
32
+ layers: layersItem[]
33
+ markers?: Object[]
34
+ }
35
+
36
+ export type AnimationAssets = {
37
+ id: string
38
+ w: number
39
+ h: number
40
+ u: string
41
+ p: string
42
+ e: number
43
+ }
@@ -0,0 +1,50 @@
1
+ // Copyright (c) 2025 Huawei Device Co., Ltd. All rights reserved
2
+ // Use of this source code is governed by a Apache-2.0 license that can be
3
+ // found in the LICENSE file.
4
+
5
+ import { ViewRawProps } from '@rnoh/react-native-openharmony'
6
+
7
+ export interface LottieViewState {}
8
+
9
+ export interface colorFiltersItem {
10
+ keypath: string;
11
+ color: string
12
+ }
13
+
14
+ export interface LottieViewProps extends ViewRawProps {
15
+ resizeMode: string
16
+ renderMode: string
17
+ sourceName: string
18
+ sourceJson: string
19
+ sourceURL: string
20
+ imageAssetsFolder: string
21
+ progress: number
22
+ speed: number
23
+ loop: boolean
24
+ autoPlay: boolean
25
+ enableMergePathsAndroidForKitKatAndAbove: boolean
26
+ hardwareAccelerationAndroid: boolean
27
+ cacheComposition: boolean
28
+ colorFilters: Array<colorFiltersItem>
29
+ }
30
+
31
+ export enum LOTTLE_STRING {
32
+ onStateChanged = 'onStateChanged',
33
+ progress = 'progress',
34
+ speed = 'speed',
35
+ loop = 'loop',
36
+ autoPlay = 'autoPlay',
37
+ onAnimationFinish = 'onAnimationFinish',
38
+ http = 'http',
39
+ contentType = 'Content-Type',
40
+ json = 'application/json',
41
+ canvas = 'canvas',
42
+ DOMLoaded = 'DOMLoaded',
43
+ colorFilters = 'colorFilters',
44
+ complete = 'complete',
45
+ play = 'play',
46
+ reset = 'reset',
47
+ pause = 'pause',
48
+ resume = 'resume',
49
+ data_failed = 'data_failed'
50
+ }
@@ -0,0 +1,18 @@
1
+ // Copyright (c) 2025 Huawei Device Co., Ltd. All rights reserved
2
+ // Use of this source code is governed by a Apache-2.0 license that can be
3
+ // found in the LICENSE file.
4
+
5
+ export function isEmpty(str: string | null | undefined): boolean {
6
+ return str == null || typeof str == 'undefined' || str.length == 0
7
+ }
8
+
9
+ export function getHashCode(str: string): string {
10
+ let hash: number = 1315423911
11
+ let i: number
12
+ let ch: number
13
+ for (i = str.length - 1; i >= 0; i--) {
14
+ ch = str.charCodeAt(i)
15
+ hash ^= ((hash << 5) + ch + (hash >> 2))
16
+ }
17
+ return (hash & 0x7FFFFFFF).toString()
18
+ }