Skip to content

Commit 8af1236

Browse files
authored
Support Lottie ZIP archive files (#587)
## What does this change? Resolves #495 🎯 ## Type of change - [x] New feature (non-breaking change which adds functionality) - [x] This change requires a documentation update
1 parent b083796 commit 8af1236

File tree

11 files changed

+94
-20
lines changed

11 files changed

+94
-20
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ Widget build(BuildContext context) {
400400
| [flutter_svg](https://pub.dev/packages/flutter_svg) | .svg | `flutter_svg: true` | Assets.images.icons.paint.**svg()** |
401401
| [flare_flutter](https://pub.dev/packages/flare_flutter) | .flr | `flare_flutter: true` | Assets.flare.penguin.**flare()** |
402402
| [rive](https://pub.dev/packages/rive) | .flr | `rive: true` | Assets.rive.vehicles.**rive()** |
403-
| [lottie](https://pub.dev/packages/lottie) | .json | `lottie: true` | Assets.lottie.hamburgerArrow.**lottie()** |
403+
| [lottie](https://pub.dev/packages/lottie) | .json, .zip | `lottie: true` | Assets.lottie.hamburgerArrow.**lottie()** |
404404

405405

406406
In other cases, the asset is generated as String class.
Binary file not shown.
201 Bytes
Binary file not shown.

examples/example/lib/gen/assets.gen.dart

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,20 @@ class $AssetsLottieGen {
8888
LottieGenImage get hamburgerArrow =>
8989
const LottieGenImage('assets/lottie/hamburger_arrow.json');
9090

91+
/// File path: assets/lottie/spinning_carrousel.zip
92+
LottieGenImage get spinningCarrousel =>
93+
const LottieGenImage('assets/lottie/spinning_carrousel.zip');
94+
9195
/// Directory path: assets/lottie/wrong
9296
$AssetsLottieWrongGen get wrong => const $AssetsLottieWrongGen();
9397

9498
/// List of all assets
95-
List<LottieGenImage> get values =>
96-
[alarmClockLottieV440, geometricalAnimation, hamburgerArrow];
99+
List<LottieGenImage> get values => [
100+
alarmClockLottieV440,
101+
geometricalAnimation,
102+
hamburgerArrow,
103+
spinningCarrousel
104+
];
97105
}
98106

99107
class $AssetsMixGen {
@@ -193,11 +201,14 @@ class $AssetsImagesIconsGen {
193201
class $AssetsLottieWrongGen {
194202
const $AssetsLottieWrongGen();
195203

204+
/// File path: assets/lottie/wrong/dummy.zip
205+
String get dummy => 'assets/lottie/wrong/dummy.zip';
206+
196207
/// File path: assets/lottie/wrong/rocket-lottie-v439.json
197208
String get rocketLottieV439 => 'assets/lottie/wrong/rocket-lottie-v439.json';
198209

199210
/// List of all assets
200-
List<String> get values => [rocketLottieV439];
211+
List<String> get values => [dummy, rocketLottieV439];
201212
}
202213

203214
class MyAssets {

packages/core/lib/generators/integrations/lottie_integration.dart

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import 'dart:convert';
22
import 'dart:io';
33

4+
import 'package:archive/archive_io.dart';
5+
import 'package:collection/collection.dart';
46
import 'package:flutter_gen_core/generators/integrations/integration.dart';
57
import 'package:path/path.dart' as p;
68
import 'package:pub_semver/pub_semver.dart';
@@ -19,6 +21,11 @@ class LottieIntegration extends Integration {
1921
'layers', // Must include layers
2022
];
2123

24+
static const _supportedMimeTypes = [
25+
'application/json',
26+
'application/zip',
27+
];
28+
2229
String get packageExpression => isPackage ? ' = package' : '';
2330

2431
@override
@@ -110,12 +117,33 @@ ${isPackage ? "\n static const String package = '$packageName';" : ''}
110117
bool get isConstConstructor => true;
111118

112119
bool isLottieFile(AssetType type) {
113-
if (type.mime != 'application/json') {
120+
if (!_supportedMimeTypes.contains(type.mime)) {
114121
return false;
115122
}
123+
if (type.mime == 'application/zip') {
124+
final inputStream = InputFileStream(type.fullPath);
125+
final archive = ZipDecoder().decodeBuffer(inputStream);
126+
final jsonFile = archive.files.firstWhereOrNull(
127+
(e) => e.name.endsWith('.json'),
128+
);
129+
if (jsonFile?.isFile != true) {
130+
return false;
131+
}
132+
final content = utf8.decode(jsonFile!.content);
133+
return _isValidJsonFile(type, overrideInput: content);
134+
}
135+
return _isValidJsonFile(type);
136+
}
137+
138+
bool _isValidJsonFile(AssetType type, {String? overrideInput}) {
116139
try {
117-
final absolutePath = p.join(type.rootPath, type.path);
118-
String input = File(absolutePath).readAsStringSync();
140+
final String input;
141+
if (overrideInput != null) {
142+
input = overrideInput;
143+
} else {
144+
final absolutePath = p.join(type.rootPath, type.path);
145+
input = File(absolutePath).readAsStringSync();
146+
}
119147
final fileKeys = jsonDecode(input) as Map<String, dynamic>;
120148
if (lottieKeys.every(fileKeys.containsKey) && fileKeys['v'] != null) {
121149
var version = Version.parse(fileKeys['v']);

packages/core/lib/settings/asset_type.dart

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import 'package:flutter_gen_core/utils/identifer.dart';
33
import 'package:flutter_gen_core/utils/string.dart';
44
import 'package:mime/mime.dart' show lookupMimeType;
55
import 'package:path/path.dart' as p;
6-
import 'package:path/path.dart';
76

87
/// https://github.com/dart-lang/mime/blob/master/lib/src/default_extension_map.dart
98
class AssetType {
@@ -40,12 +39,15 @@ class AssetType {
4039

4140
bool get isUnKnownMime => mime == null;
4241

43-
String get extension => p.extension(path);
42+
/// Returns a name for this asset.
43+
String get name => p.withoutExtension(path);
4444

4545
String get baseName => p.basenameWithoutExtension(path);
4646

47+
String get extension => p.extension(path);
48+
4749
/// Returns the full absolute path for reading the asset file.
48-
String get fullPath => join(rootPath, path);
50+
String get fullPath => p.join(rootPath, path);
4951

5052
// Replace to Posix style for Windows separator.
5153
String get posixStylePath => path.replaceAll(r'\', r'/');
@@ -56,10 +58,12 @@ class AssetType {
5658
_children.add(type);
5759
}
5860

59-
/// Returns a name for this asset.
60-
String get name {
61-
return withoutExtension(path);
62-
}
61+
@override
62+
String toString() => 'AssetType('
63+
'rootPath: $rootPath, '
64+
'path: $path, '
65+
'flavors: $flavors'
66+
')';
6367
}
6468

6569
/// Represents a AssetType with modifiers on it to mutate the [name] to ensure
@@ -99,15 +103,14 @@ class UniqueAssetType extends AssetType {
99103
String get name {
100104
// Omit root directory from the name if it is either asset or assets.
101105
// TODO(bramp): Maybe move this into the _flatStyleDefinition
102-
String p = path.replaceFirst(RegExp(r'^asset(s)?[/\\]'), '');
106+
String result = path.replaceFirst(RegExp(r'^asset(s)?[/\\]'), '');
103107
if (basenameOnly) {
104-
p = basename(p);
108+
result = p.basename(result);
105109
}
106110
if (!needExtension) {
107-
p = withoutExtension(p);
111+
result = p.withoutExtension(result);
108112
}
109-
110-
return style(convertToIdentifier(p)) + suffix;
113+
return style(convertToIdentifier(result)) + suffix;
111114
}
112115

113116
@override

packages/core/pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ dependencies:
2525
glob: ^2.0.0
2626

2727
dart_style: ^2.2.4
28+
archive: ^3.4.0
2829
args: ^2.0.0
2930
pub_semver: ^2.0.0
3031
vector_graphics_compiler: ^1.1.9

packages/core/test/config_test.dart renamed to packages/core/test/settings_test.dart

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,34 @@
11
import 'package:collection/collection.dart';
2+
import 'package:flutter_gen_core/settings/asset_type.dart';
23
import 'package:flutter_gen_core/settings/flavored_asset.dart';
34
import 'package:test/test.dart';
45

56
void main() {
7+
group(AssetType, () {
8+
test('constructor', () {
9+
final assetType = AssetType(
10+
rootPath: 'root',
11+
path: 'assets/single.jpg',
12+
flavors: {'flavor'},
13+
);
14+
expect(assetType, isA<AssetType>());
15+
expect(assetType.name, 'assets/single');
16+
expect(assetType.baseName, 'single');
17+
expect(assetType.extension, '.jpg');
18+
expect(assetType.isUnKnownMime, false);
19+
expect(
20+
assetType,
21+
predicate<AssetType>(
22+
(e) => SetEquality().equals(e.flavors, {'flavor'}),
23+
),
24+
);
25+
expect(
26+
assetType.toString(),
27+
'AssetType(rootPath: root, path: assets/single.jpg, flavors: {flavor})',
28+
);
29+
});
30+
});
31+
632
group(FlavoredAsset, () {
733
test('constructor', () {
834
expect(

packages/core/test_resources/actual_data/assets_lottie_integrations.gen.dart

Lines changed: 5 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Binary file not shown.

0 commit comments

Comments
 (0)