Skip to content

Commit

Permalink
Add Lottie integration (#298)
Browse files Browse the repository at this point in the history
* Add lottie integration
* example & test asset
* auto strip "lottie" from final asset var name

* Update README.md

* Update lottie integration
* dropped support for '*_lottie.json' per #70 PR
* include root path for tests
* update example

* set: min lottie version
* rename resourcesPath for better code readability

* fix: version must be equals or more than 4.4.0

* fix merge

* support semver

* change custom semver to pub_sem_ver

* chore: add some usecases files

* refactor: change to named constructor

* test: add wrong test case

Co-authored-by: Alexandra Kovaleva <realmousy@gmail.com>
  • Loading branch information
wasabeef and onlymice committed Sep 28, 2022
1 parent 7735309 commit 9e10a6e
Show file tree
Hide file tree
Showing 22 changed files with 496 additions and 16 deletions.
4 changes: 4 additions & 0 deletions README.md
Expand Up @@ -124,6 +124,7 @@ flutter_gen:
flutter_svg: true
flare_flutter: true
rive: true
lottie: true

colors:
inputs:
Expand Down Expand Up @@ -225,6 +226,8 @@ Widget build(BuildContext context) {
|[flutter_svg](https://pub.dev/packages/flutter_svg)|.svg| `flutter_svg: true` |Assets.images.icons.paint.**svg()**|
|[flare_flutter](https://pub.dev/packages/flare_flutter)|.flr| `flare_flutter: true` |Assets.flare.penguin.**flare()**|
|[rive](https://pub.dev/packages/rive)|.flr| `rive: true` |Assets.rive.vehicles.**rive()**|
|[lottie](https://pub.dev/packages/lottie)|_lottie.json| `lottie: true` |Assets.lottie.hamburgerArrow.**lottie()**|


<br/>

Expand Down Expand Up @@ -725,6 +728,7 @@ flutter_gen:
flutter_svg: false
flare_flutter: false
rive: false
lottie: false

assets:
# Optional
Expand Down
1 change: 1 addition & 0 deletions example/assets/lottie/alarm-clock-lottie-v440.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions example/assets/lottie/geometrical-animation.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions example/assets/lottie/hamburger_arrow.json
@@ -0,0 +1 @@
{"assets":[],"layers":[{"ddd":0,"ind":0,"ty":3,"nm":"Rotator","ks":{"o":{"k":0},"r":{"k":[{"i":{"x":[0.56],"y":[1]},"o":{"x":[0.634],"y":[0]},"n":["0p56_1_0p634_0"],"t":19,"s":[0],"e":[190.7]},{"i":{"x":[0.562],"y":[1]},"o":{"x":[0.398],"y":[0]},"n":["0p562_1_0p398_0"],"t":33,"s":[190.7],"e":[176.1]},{"i":{"x":[0.684],"y":[1]},"o":{"x":[0.31],"y":[0]},"n":["0p684_1_0p31_0"],"t":40.5,"s":[176.1],"e":[181.8]},{"i":{"x":[0.684],"y":[1]},"o":{"x":[0.438],"y":[0]},"n":["0p684_1_0p438_0"],"t":55,"s":[181.8],"e":[180]},{"i":{"x":[0.733],"y":[0.733]},"o":{"x":[0.385],"y":[0.385]},"n":["0p733_0p733_0p385_0p385"],"t":71,"s":[180],"e":[180]},{"i":{"x":[0.092],"y":[1]},"o":{"x":[0.406],"y":[0]},"n":["0p092_1_0p406_0"],"t":111,"s":[180],"e":[167.9]},{"i":{"x":[0.341],"y":[1]},"o":{"x":[0.6],"y":[0]},"n":["0p341_1_0p6_0"],"t":116,"s":[167.9],"e":[363]},{"i":{"x":[0.462],"y":[1]},"o":{"x":[0.167],"y":[0]},"n":["0p462_1_0p167_0"],"t":134,"s":[363],"e":[360]},{"t":141}]},"p":{"k":[200.5,149.375,0]},"a":{"k":[60,60,0]},"s":{"k":[100,100,100]}},"ao":0,"ip":0,"op":180,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":1,"ty":4,"nm":"A1","parent":0,"ks":{"o":{"k":100},"r":{"k":[{"i":{"x":[0.56],"y":[1]},"o":{"x":[0.634],"y":[0]},"n":["0p56_1_0p634_0"],"t":19,"s":[0],"e":[-45]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":33,"s":[-45],"e":[-45]},{"i":{"x":[0.341],"y":[1]},"o":{"x":[0.6],"y":[0]},"n":["0p341_1_0p6_0"],"t":116,"s":[-45],"e":[0]},{"t":134}]},"p":{"k":[{"i":{"x":0.56,"y":1},"o":{"x":0.634,"y":0},"n":"0p56_1_0p634_0","t":19,"s":[94.5,82.875,0],"e":[96.2,57.055,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":0},"o":{"x":0.167,"y":0.167},"n":"0_0_0p167_0p167","t":33,"s":[96.2,57.055,0],"e":[96.2,57.055,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.341,"y":1},"o":{"x":0.6,"y":0},"n":"0p341_1_0p6_0","t":116,"s":[96.2,57.055,0],"e":[94.5,82.875,0],"to":[0,0,0],"ti":[0,0,0]},{"t":134}]},"a":{"k":[35,22.25,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-34,22.25],[35,22.25]],"c":false}},"nm":"Path 1"},{"ty":"st","fillEnabled":true,"c":{"k":[0.4,0.16,0.7,1]},"o":{"k":100},"w":{"k":10},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1"},{"ty":"tm","s":{"k":[{"i":{"x":[0.56],"y":[1]},"o":{"x":[0.634],"y":[0]},"n":["0p56_1_0p634_0"],"t":19,"s":[0],"e":[26]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":33,"s":[26],"e":[26]},{"i":{"x":[0.341],"y":[1]},"o":{"x":[0.6],"y":[0]},"n":["0p341_1_0p6_0"],"t":116,"s":[26],"e":[0]},{"t":134}],"ix":1},"e":{"k":[{"i":{"x":[0.56],"y":[0.56]},"o":{"x":[0.634],"y":[0.634]},"n":["0p56_0p56_0p634_0p634"],"t":19,"s":[100],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":33,"s":[100],"e":[100]},{"i":{"x":[0.341],"y":[0.341]},"o":{"x":[0.6],"y":[0.6]},"n":["0p341_0p341_0p6_0p6"],"t":116,"s":[100],"e":[100]},{"t":134}],"ix":2},"o":{"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1"}],"ip":0,"op":180,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":2,"ty":4,"nm":"A2","parent":0,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[60,60.625,0]},"a":{"k":[0.5,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-34,0],[35,0]],"c":false}},"nm":"Path 1"},{"ty":"st","fillEnabled":true,"c":{"k":[0.4,0.16,0.7,1]},"o":{"k":100},"w":{"k":10},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1"}],"ip":0,"op":180,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":3,"ty":4,"nm":"A3","parent":0,"ks":{"o":{"k":100},"r":{"k":[{"i":{"x":[0.56],"y":[1]},"o":{"x":[0.634],"y":[0]},"n":["0p56_1_0p634_0"],"t":19,"s":[0],"e":[45]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":33,"s":[45],"e":[45]},{"i":{"x":[0.341],"y":[1]},"o":{"x":[0.6],"y":[0]},"n":["0p341_1_0p6_0"],"t":116,"s":[45],"e":[0]},{"t":134}]},"p":{"k":[{"i":{"x":0.56,"y":1},"o":{"x":0.634,"y":0},"n":"0p56_1_0p634_0","t":19,"s":[94.5,37.125,0],"e":[96.2,64.045,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":0},"o":{"x":0.167,"y":0.167},"n":"0_0_0p167_0p167","t":33,"s":[96.2,64.045,0],"e":[96.2,64.045,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.341,"y":1},"o":{"x":0.6,"y":0},"n":"0p341_1_0p6_0","t":116,"s":[96.2,64.045,0],"e":[94.5,37.125,0],"to":[0,0,0],"ti":[0,0,0]},{"t":134}]},"a":{"k":[35,-23.5,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-34,-23.5],[35,-23.5]],"c":false}},"nm":"Path 1"},{"ty":"st","fillEnabled":true,"c":{"k":[0.4,0.16,0.7,1]},"o":{"k":100},"w":{"k":10},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1"},{"ty":"tm","s":{"k":[{"i":{"x":[0.56],"y":[1]},"o":{"x":[0.634],"y":[0]},"n":["0p56_1_0p634_0"],"t":19,"s":[0],"e":[26]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":33,"s":[26],"e":[26]},{"i":{"x":[0.341],"y":[1]},"o":{"x":[0.6],"y":[0]},"n":["0p341_1_0p6_0"],"t":116,"s":[26],"e":[0]},{"t":134}],"ix":1},"e":{"k":[{"i":{"x":[0.56],"y":[0.56]},"o":{"x":[0.634],"y":[0.634]},"n":["0p56_0p56_0p634_0p634"],"t":19,"s":[100],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":33,"s":[100],"e":[100]},{"i":{"x":[0.341],"y":[0.341]},"o":{"x":[0.6],"y":[0.6]},"n":["0p341_0p341_0p6_0p6"],"t":116,"s":[100],"e":[100]},{"t":134}],"ix":2},"o":{"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1"}],"ip":0,"op":180,"st":0,"bm":0,"sr":1}],"v":"4.4.26","ddd":0,"ip":0,"op":180,"fr":30,"w":400,"h":300}
1 change: 1 addition & 0 deletions example/assets/lottie/wrong/rocket-lottie-v439.json

Large diffs are not rendered by default.

90 changes: 90 additions & 0 deletions example/lib/gen/assets.gen.dart
Expand Up @@ -13,6 +13,7 @@ import 'package:flutter/services.dart';
import 'package:flare_flutter/flare_actor.dart';
import 'package:flare_flutter/flare_controller.dart';
import 'package:rive/rive.dart';
import 'package:lottie/lottie.dart';

class $AssetsFlareGen {
const $AssetsFlareGen();
Expand Down Expand Up @@ -62,6 +63,28 @@ class $AssetsJsonGen {
List<String> get values => [fruits];
}

class $AssetsLottieGen {
const $AssetsLottieGen();

/// File path: assets/lottie/alarm-clock-lottie-v440.json
LottieGenImage get alarmClockLottieV440 =>
const LottieGenImage('assets/lottie/alarm-clock-lottie-v440.json');

/// File path: assets/lottie/geometrical-animation.json
LottieGenImage get geometricalAnimation =>
const LottieGenImage('assets/lottie/geometrical-animation.json');

/// File path: assets/lottie/hamburger_arrow.json
LottieGenImage get hamburgerArrow =>
const LottieGenImage('assets/lottie/hamburger_arrow.json');

$AssetsLottieWrongGen get wrong => const $AssetsLottieWrongGen();

/// List of all assets
List<LottieGenImage> get values =>
[alarmClockLottieV440, geometricalAnimation, hamburgerArrow];
}

class $AssetsMovieGen {
const $AssetsMovieGen();

Expand Down Expand Up @@ -130,12 +153,23 @@ class $AssetsImagesIconsGen {
List<SvgGenImage> get values => [dartTest, fuchsia, kmm, paint];
}

class $AssetsLottieWrongGen {
const $AssetsLottieWrongGen();

/// File path: assets/lottie/wrong/rocket-lottie-v439.json
String get rocketLottieV439 => 'assets/lottie/wrong/rocket-lottie-v439.json';

/// List of all assets
List<String> get values => [rocketLottieV439];
}

class MyAssets {
MyAssets._();

static const $AssetsFlareGen flare = $AssetsFlareGen();
static const $AssetsImagesGen images = $AssetsImagesGen();
static const $AssetsJsonGen json = $AssetsJsonGen();
static const $AssetsLottieGen lottie = $AssetsLottieGen();
static const $AssetsMovieGen movie = $AssetsMovieGen();
static const $AssetsRiveGen rive = $AssetsRiveGen();
static const $AssetsUnknownGen unknown = $AssetsUnknownGen();
Expand Down Expand Up @@ -328,3 +362,59 @@ class RiveGenImage {

String get path => _assetName;
}

class LottieGenImage {
const LottieGenImage(this._assetName);

final String _assetName;

LottieBuilder lottie({
Animation<double>? controller,
bool? animate,
FrameRate? frameRate,
bool? repeat,
bool? reverse,
LottieDelegates? delegates,
LottieOptions? options,
void Function(LottieComposition)? onLoaded,
LottieImageProviderFactory? imageProviderFactory,
Key? key,
AssetBundle? bundle,
Widget Function(BuildContext, Widget, LottieComposition?)? frameBuilder,
ImageErrorWidgetBuilder? errorBuilder,
double? width,
double? height,
BoxFit? fit,
AlignmentGeometry? alignment,
String? package,
bool? addRepaintBoundary,
FilterQuality? filterQuality,
void Function(String)? onWarning,
}) {
return Lottie.asset(
_assetName,
animate: animate,
frameRate: frameRate,
repeat: repeat,
reverse: reverse,
delegates: delegates,
options: options,
onLoaded: onLoaded,
imageProviderFactory: imageProviderFactory,
key: key,
bundle: bundle,
frameBuilder: frameBuilder,
errorBuilder: errorBuilder,
width: width,
height: height,
fit: fit,
alignment: alignment,
package: package,
addRepaintBoundary: addRepaintBoundary,
filterQuality: filterQuality,
onWarning: onWarning,
);
}

String get path => _assetName;
}
21 changes: 21 additions & 0 deletions example/lib/main.dart
Expand Up @@ -43,6 +43,27 @@ void main() async {
fit: BoxFit.contain,
),
),
SizedBox(
width: 200,
height: 200,
child: MyAssets.lottie.hamburgerArrow.lottie(
fit: BoxFit.contain,
),
),
SizedBox(
width: 200,
height: 200,
child: MyAssets.lottie.geometricalAnimation.lottie(
fit: BoxFit.contain,
),
),
SizedBox(
width: 200,
height: 200,
child: MyAssets.lottie.alarmClockLottieV440.lottie(
fit: BoxFit.contain,
),
),
MyAssets.images.chip1.image(),
Container(
height: 400,
Expand Down
5 changes: 4 additions & 1 deletion example/pubspec.yaml
Expand Up @@ -57,7 +57,7 @@ dependencies:
flutter_secure_storage: 5.0.2
auto_route: 3.2.4
gap: 2.0.0
lottie: 1.3.0
lottie: 1.4.1
flutter_layout_grid: 2.0.0
video_player: 2.4.0
audio_service: 0.18.4
Expand Down Expand Up @@ -119,6 +119,7 @@ flutter_gen:
flutter_svg: true
flare_flutter: true
rive: true
lottie: true

assets:
enabled: true
Expand Down Expand Up @@ -169,6 +170,8 @@ flutter:
- pictures/chip5.jpg
- assets/flare/
- assets/rive/
- assets/lottie/
- assets/lottie/wrong/
- assets/movie/
- assets/unknown/
fonts:
Expand Down
7 changes: 7 additions & 0 deletions packages/core/example/lib/main.dart
Expand Up @@ -38,6 +38,13 @@ void main() {
fit: BoxFit.contain,
),
),
SizedBox(
width: 200,
height: 200,
child: Assets.lottie.hamburgerArrow.lottie(
fit: BoxFit.contain,
),
),
Image(image: Assets.images.chip1),
Assets.images.icons.kmm.svg(key: const Key("kmm_svg")),
Assets.images.icons.fuchsia.svg(),
Expand Down
16 changes: 10 additions & 6 deletions packages/core/lib/generators/assets_generator.dart
Expand Up @@ -17,6 +17,7 @@ import 'integrations/flare_integration.dart';
import 'integrations/integration.dart';
import 'integrations/rive_integration.dart';
import 'integrations/svg_integration.dart';
import 'integrations/lottie_integration.dart';

class AssetsGenConfig {
AssetsGenConfig._(
Expand All @@ -29,7 +30,7 @@ class AssetsGenConfig {

factory AssetsGenConfig.fromConfig(File pubspecFile, Config config) {
return AssetsGenConfig._(
pubspecFile.parent.path,
pubspecFile.parent.absolute.path,
config.pubspec.packageName,
config.pubspec.flutterGen,
config.pubspec.flutter.assets,
Expand Down Expand Up @@ -66,6 +67,7 @@ String generateAssets(
SvgIntegration(config.packageParameterLiteral),
if (config.flutterGen.integrations.flareFlutter) FlareIntegration(),
if (config.flutterGen.integrations.rive) RiveIntegration(),
if (config.flutterGen.integrations.lottie) LottieIntegration(),
];

// TODO: This code will be removed.
Expand Down Expand Up @@ -213,15 +215,17 @@ List<String> _getAssetRelativePathList(
.toList();
}

AssetType _constructAssetTree(List<String> assetRelativePathList) {
AssetType _constructAssetTree(
List<String> assetRelativePathList, String rootPath) {
// Relative path is the key
final assetTypeMap = <String, AssetType>{
'.': AssetType('.'),
'.': AssetType(rootPath: rootPath, path: '.'),
};
for (final assetPath in assetRelativePathList) {
var path = assetPath;
while (path != '.') {
assetTypeMap.putIfAbsent(path, () => AssetType(path));
assetTypeMap.putIfAbsent(
path, () => AssetType(rootPath: rootPath, path: path));
path = dirname(path);
}
}
Expand Down Expand Up @@ -309,7 +313,7 @@ String _dotDelimiterStyleDefinition(
final assetsStaticStatements = <_Statement>[];

final assetTypeQueue = ListQueue<AssetType>.from(
_constructAssetTree(assetRelativePathList).children);
_constructAssetTree(assetRelativePathList, config.rootPath).children);

while (assetTypeQueue.isNotEmpty) {
final assetType = assetTypeQueue.removeFirst();
Expand Down Expand Up @@ -404,7 +408,7 @@ String _flatStyleDefinition(
)
.distinct()
.sorted()
.map((relativePath) => AssetType(relativePath))
.map((assetPath) => AssetType(rootPath: config.rootPath, path: assetPath))
.mapToIsUniqueWithoutExtension()
.map(
(e) => _createAssetTypeStatement(
Expand Down
118 changes: 118 additions & 0 deletions packages/core/lib/generators/integrations/lottie_integration.dart
@@ -0,0 +1,118 @@
import 'package:pub_semver/pub_semver.dart';

import '../../settings/asset_type.dart';
import 'integration.dart';
import 'dart:convert';
import 'dart:io';
import 'package:path/path.dart' as p;

class LottieIntegration extends Integration {
// These are required keys for this integration.
static const lottieKeys = [
'w', // width
'h', // height
'ip', // The frame at which the Lottie animation starts at
'op', // The frame at which the Lottie animation ends at
'fr', // frame rate
'v', // // Must include version
'layers', // Must include layers
];

@override
List<String> get requiredImports => [
'package:lottie/lottie.dart',
];

@override
String get classOutput => _classDefinition;

final String _classDefinition = '''class LottieGenImage {
const LottieGenImage(this._assetName);
final String _assetName;
LottieBuilder lottie({
Animation<double>? controller,
bool? animate,
FrameRate? frameRate,
bool? repeat,
bool? reverse,
LottieDelegates? delegates,
LottieOptions? options,
void Function(LottieComposition)? onLoaded,
LottieImageProviderFactory? imageProviderFactory,
Key? key,
AssetBundle? bundle,
Widget Function(BuildContext, Widget, LottieComposition?)? frameBuilder,
ImageErrorWidgetBuilder? errorBuilder,
double? width,
double? height,
BoxFit? fit,
AlignmentGeometry? alignment,
String? package,
bool? addRepaintBoundary,
FilterQuality? filterQuality,
void Function(String)? onWarning,
}) {
return Lottie.asset(
_assetName,
animate: animate,
frameRate: frameRate,
repeat: repeat,
reverse: reverse,
delegates: delegates,
options: options,
onLoaded: onLoaded,
imageProviderFactory: imageProviderFactory,
key: key,
bundle: bundle,
frameBuilder: frameBuilder,
errorBuilder: errorBuilder,
width: width,
height: height,
fit: fit,
alignment: alignment,
package: package,
addRepaintBoundary: addRepaintBoundary,
filterQuality: filterQuality,
onWarning: onWarning,
);
}
String get path => _assetName;
}''';

@override
String get className => 'LottieGenImage';

@override
String classInstantiate(String path) => 'LottieGenImage(\'$path\')';

@override
bool isSupport(AssetType type) => isLottieFile(type);

@override
bool get isConstConstructor => true;

bool isLottieFile(AssetType type) {
if (type.mime != 'application/json') {
return false;
}
try {
final absolutePath = p.join(type.rootPath, type.path);
String input = File(absolutePath).readAsStringSync();
final fileKeys = jsonDecode(input) as Map<String, dynamic>;
if (lottieKeys.every((key) => fileKeys.containsKey(key)) &&
fileKeys['v'] != null) {
var version = Version.parse(fileKeys['v']);
// Lottie version 4.4.0 is the first version that supports BodyMovin.
// https://github.com/xvrh/lottie-flutter/blob/0e7499d82ea1370b6acf023af570395bbb59b42f/lib/src/parser/lottie_composition_parser.dart#L60
return version >= Version(4, 4, 0);
}
} on FormatException catch (e) {
// Catches bad/corrupted json and reports it to user.
stderr.writeln(e.message);
}
return false;
}
}

0 comments on commit 9e10a6e

Please sign in to comment.