flutter_gen
flutter_gen copied to clipboard
Add Lottie integration
What does this change?
-
Adds lottie integration.
-
Checks for lottie files by in json tags
-
Example includes on how to use it
-
Docs changed accordingly
Related
Initial Feature Request: https://github.com/FlutterGen/flutter_gen/issues/47 Previous PR that tried to introduce support for Lottie: https://github.com/FlutterGen/flutter_gen/pull/70
What's different now?
Previously HiroyukiTamura https://github.com/FlutterGen/flutter_gen/pull/70 implemented a Lottie integration per request https://github.com/FlutterGen/flutter_gen/issues/47#issuecomment-1151910798 but as stated by britannio's https://github.com/FlutterGen/flutter_gen/pull/70#issuecomment-769968336 in the initial PR, their implementation will be better off checking for keys in the file itself, rather than only it's extension *_lottie.json as it was initially requested two years ago.
So I did.
Other issues
Why there is a lot of changes to tests
Initially Implementation of this feature required File read access, there was no issues with that if you run code as designed e.g
flutter packages pub run build_runner build
But if you try to run tests you might ended up seeing that the relative asset path that you get in isSupport is not relative to the Directory.current.path and the code in 'packages/core/lib' can't access it while running tests.
So I introduced mocked rootPath #assets_gen_integrations_test.dart#L13 for tests and now the AssetType has field for absolutePath that is constructed from the passed rootPath (config.rootPath) and the key/path.
Other integrations haven't tried to read files, cause they don't need it, so here we are, feel free to propose a better solution.
What is the value of this and can you measure success?
Measure
-
Pass tests.
-
No linting issues with generated code.
-
Example runs, plays the animation and works well.
Value
- Others who tends to use Lottie in their projects will be happy to know that flutter_gen supports it
For Discussion
-
I have set a strict version for
lottie: '>=1.4.1 <2.0.0'because lower versions accept different types for parameters. 1.1. we can usedynamicand recheck for allowedruntimeTypein generated constructor. 1.2. leave as is. -
keys are checked by
everywith listlottieKeysthat must be included in the file for Lottie to render it properly, the thing is that I haven't found the exact specification for what keys are required (and other libs don't even care if they don't exist), in fact the only thing I have found is that the version in the flutter Lottie package is set to check for >=4.4.0, and layers is where most of the data are. 2.1. choose what keys are actually required. 2.2. leave as is.
@onlymice
Thank you for your nice PR. I'll check it next week, so please wait. 🙏🏽
My codes.
integration.dart
abstract class Integration {
// ..
bool isSupport(AssetType type, {String? rootPath});
// ..
}
svg/rive/flare integratinos.dart
class SvgIntegration extends Integration {
// ..
@override
bool isSupport(AssetType type, {String? rootPath}) => type.mime == 'image/svg+xml';
// ..
}
lottie integratinos.dart
class LottieIntegration extends Integration {
// ..
@override
bool isSupport(AssetType type, {String? rootPath}) =>
isLottieFile(type, rootPath ?? p.current);
@override
bool get isConstConstructor => true;
bool isLottieFile(AssetType type, String rootPath) {
if (!type.path.endsWith('.json')) {
return false;
}
var input = File(p.join(rootPath, type.path)).readAsStringSync();
var fileKeys = jsonDecode(input);
if (fileKeys.runtimeType != Map &&
!lottieKeys.every((key) => fileKeys.containsKey(key))) {
return false;
}
var versions = fileKeys['v'];
if (versions is! String) {
return false;
}
var version = int.tryParse(versions.replaceAll('.', '')) ?? 0;
// 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 / 1000 >= 0.440;
}
// ..
}
assets_generator.dart
// ... only this
(element) => element.isSupport(assetType, rootPath: rootPath),
// ...
assets_gen_integrations_test.dart
// No change except here
// only add.
test('Assets with Lottie integrations on pubspec.yaml', () async {
const pubspec = 'test_resources/pubspec_assets_lottie_integrations.yaml';
const fact =
'test_resources/actual_data/assets_lottie_integrations.gen.dart';
const generated =
'test_resources/lib/gen/assets_lottie_integrations.gen.dart';
await expectedAssetsGen(pubspec, generated, fact);
final integration = LottieIntegration();
expect(integration.className, 'LottieGenImage');
expect(integration.classInstantiate('assets/lottie'),
'LottieGenImage(\'assets/lottie\')');
final testResPath = p.absolute('test_resources'); // 🌟
expect(
integration.isSupport(AssetType('assets/lottie/hamburger_arrow.json'),
rootPath: testResPath), // 🌟
isTrue);
expect(
integration.isSupport(
AssetType('assets/lottie/hamburger_arrow_without_version.json'),
rootPath: testResPath),
isFalse);
expect(integration.isConstConstructor, isTrue);
});
@onlymice Thanks for the great suggestions for a lottie users and me.
Hi @wasabeef, Hope you doing well, I'm pinging you because I've decided to use a proper semver, my bad for not going with it initially 😅
updated code 🎯
bool isLottieFile(AssetType type) {
try {
if (type.extension != '.json') {
return false;
}
String input = File(type.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;
}
Hi @onlymice, I've merged #298 based on your PR codes created, it changed a few variable names, etc. Thank you so much. We will be releasing v5.0.0 soon.