From eec330e7907f9f8489d5c6b964bd37c35e71e891 Mon Sep 17 00:00:00 2001 From: Alex Li Date: Sun, 16 Jun 2024 10:54:37 +0800 Subject: [PATCH 01/14] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20Adds=20the=20compati?= =?UTF-8?q?bility=20of=20flavored=20assets=20declaration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/lib/generators/assets_generator.dart | 13 ++++++++++--- packages/core/lib/settings/pubspec.dart | 2 +- packages/core/lib/settings/pubspec.g.dart | 2 +- packages/runner/lib/flutter_gen_runner.dart | 17 ++++++++++++++--- packages/runner/pubspec.yaml | 1 + 5 files changed, 27 insertions(+), 8 deletions(-) diff --git a/packages/core/lib/generators/assets_generator.dart b/packages/core/lib/generators/assets_generator.dart index 60d638aec..e923fb5ee 100644 --- a/packages/core/lib/generators/assets_generator.dart +++ b/packages/core/lib/generators/assets_generator.dart @@ -18,6 +18,7 @@ import 'package:flutter_gen_core/utils/error.dart'; import 'package:flutter_gen_core/utils/string.dart'; import 'package:glob/glob.dart'; import 'package:path/path.dart'; +import 'package:yaml/yaml.dart'; class AssetsGenConfig { AssetsGenConfig._( @@ -41,7 +42,7 @@ class AssetsGenConfig { final String rootPath; final String _packageName; final FlutterGen flutterGen; - final List assets; + final List assets; final List exclude; String get packageParameterLiteral => @@ -200,13 +201,19 @@ List _getAssetRelativePathList( String rootPath, /// List of assets as provided the `flutter`.`assets` section in the pubspec.yaml. - List assets, + List assets, /// List of globs as provided the `flutter_gen`.`assets`.`exclude` section in the pubspec.yaml. List excludes, ) { final assetRelativePathList = []; - for (final assetName in assets) { + for (final asset in assets) { + final String assetName; + if (asset is YamlMap) { + assetName = asset['path'] as String; + } else { + assetName = asset as String; + } final assetAbsolutePath = join(rootPath, assetName); if (FileSystemEntity.isDirectorySync(assetAbsolutePath)) { assetRelativePathList.addAll(Directory(assetAbsolutePath) diff --git a/packages/core/lib/settings/pubspec.dart b/packages/core/lib/settings/pubspec.dart index f2592a4e7..62436f6b5 100644 --- a/packages/core/lib/settings/pubspec.dart +++ b/packages/core/lib/settings/pubspec.dart @@ -32,7 +32,7 @@ class Flutter { }); @JsonKey(name: 'assets', required: true) - final List assets; + final List assets; @JsonKey(name: 'fonts', required: true) final List fonts; diff --git a/packages/core/lib/settings/pubspec.g.dart b/packages/core/lib/settings/pubspec.g.dart index 9945fcdb5..c03f15b07 100644 --- a/packages/core/lib/settings/pubspec.g.dart +++ b/packages/core/lib/settings/pubspec.g.dart @@ -36,7 +36,7 @@ Flutter _$FlutterFromJson(Map json) => $checkedCreate( ); final val = Flutter( assets: $checkedConvert('assets', - (v) => (v as List).map((e) => e as String).toList()), + (v) => (v as List).map((e) => e as Object).toList()), fonts: $checkedConvert( 'fonts', (v) => (v as List) diff --git a/packages/runner/lib/flutter_gen_runner.dart b/packages/runner/lib/flutter_gen_runner.dart index e3b047ec4..03ab755b5 100644 --- a/packages/runner/lib/flutter_gen_runner.dart +++ b/packages/runner/lib/flutter_gen_runner.dart @@ -8,6 +8,7 @@ import 'package:flutter_gen_core/flutter_generator.dart'; import 'package:flutter_gen_core/settings/config.dart'; import 'package:glob/glob.dart'; import 'package:path/path.dart'; +import 'package:yaml/yaml.dart'; Builder build(BuilderOptions options) => FlutterGenBuilder(); @@ -62,9 +63,19 @@ class FlutterGenBuilder extends Builder { final HashSet assets = HashSet(); if (pubspec.flutterGen.assets.enabled) { - for (var assetInput in pubspec.flutter.assets) { - if (assetInput.isEmpty) continue; - if (assetInput.endsWith('/')) assetInput += '*'; + for (final asset in pubspec.flutter.assets) { + String assetInput; + if (asset is YamlMap) { + assetInput = asset['path'] as String; + } else { + assetInput = asset as String; + } + if (assetInput.isEmpty) { + continue; + } + if (assetInput.endsWith('/')) { + assetInput += '*'; + } await for (final assetId in buildStep.findAssets(Glob(assetInput))) { assets.add(assetId.path); } diff --git a/packages/runner/pubspec.yaml b/packages/runner/pubspec.yaml index e35371b03..fa12a4777 100644 --- a/packages/runner/pubspec.yaml +++ b/packages/runner/pubspec.yaml @@ -16,6 +16,7 @@ dependencies: crypto: ^3.0.0 glob: ^2.0.0 path: ^1.8.0 + yaml: ^3.0.0 dev_dependencies: lints: any # Ignoring the version to allow editing across SDK versions. From 3d71d4b9b5f6d50bacaab02994a11a2b553aa011 Mon Sep 17 00:00:00 2001 From: Alex Li Date: Mon, 17 Jun 2024 22:23:36 +0800 Subject: [PATCH 02/14] =?UTF-8?q?=E2=9C=A8=20Introduce=20`FlavoredAsset`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/example/pubspec.yaml | 5 +- .../core/lib/generators/assets_generator.dart | 67 +++++++++++------- .../integrations/flare_integration.dart | 11 +-- .../integrations/image_integration.dart | 35 +++++++--- .../generators/integrations/integration.dart | 17 ++++- .../integrations/lottie_integration.dart | 11 +-- .../integrations/rive_integration.dart | 11 +-- .../integrations/svg_integration.dart | 69 +++++++++++++------ packages/core/lib/settings/asset_type.dart | 13 +++- .../core/lib/settings/flavored_asset.dart | 16 +++++ 10 files changed, 183 insertions(+), 72 deletions(-) create mode 100644 packages/core/lib/settings/flavored_asset.dart diff --git a/examples/example/pubspec.yaml b/examples/example/pubspec.yaml index fd9faa368..411f14017 100644 --- a/examples/example/pubspec.yaml +++ b/examples/example/pubspec.yaml @@ -76,7 +76,6 @@ flutter: - assets/images/ - assets/images/chip3/chip3.jpg - assets/images/chip3/chip3.jpg # duplicated - - assets/images/chip4/ - assets/images/icons/fuchsia.svg - assets/images/icons/kmm.svg - assets/images/icons/paint.svg @@ -91,6 +90,10 @@ flutter: - assets/mix/ - assets-extern/ - pictures/chip5.jpg + + - path: assets/images/chip4/chip4.jpg + flavors: + - extern fonts: - family: Raleway fonts: diff --git a/packages/core/lib/generators/assets_generator.dart b/packages/core/lib/generators/assets_generator.dart index e923fb5ee..c727e87e7 100644 --- a/packages/core/lib/generators/assets_generator.dart +++ b/packages/core/lib/generators/assets_generator.dart @@ -13,6 +13,7 @@ import 'package:flutter_gen_core/generators/integrations/rive_integration.dart'; import 'package:flutter_gen_core/generators/integrations/svg_integration.dart'; import 'package:flutter_gen_core/settings/asset_type.dart'; import 'package:flutter_gen_core/settings/config.dart'; +import 'package:flutter_gen_core/settings/flavored_asset.dart'; import 'package:flutter_gen_core/settings/pubspec.dart'; import 'package:flutter_gen_core/utils/error.dart'; import 'package:flutter_gen_core/utils/string.dart'; @@ -195,34 +196,43 @@ String? generatePackageNameForConfig(AssetsGenConfig config) { } } -/// Returns a list of all releative path assets that are to be considered. -List _getAssetRelativePathList( +/// Returns a list of all relative path assets that are to be considered. +List _getAssetRelativePathList( /// The absolute root path of the assets directory. String rootPath, - /// List of assets as provided the `flutter`.`assets` section in the pubspec.yaml. + /// List of assets as provided the `flutter -> assets` + /// section in the pubspec.yaml. List assets, - /// List of globs as provided the `flutter_gen`.`assets`.`exclude` section in the pubspec.yaml. + /// List of globs as provided the `flutter_gen -> assets -> exclude` + /// section in the pubspec.yaml. List excludes, ) { - final assetRelativePathList = []; + final assetRelativePathList = []; for (final asset in assets) { - final String assetName; + final FlavoredAsset tempAsset; if (asset is YamlMap) { - assetName = asset['path'] as String; + tempAsset = FlavoredAsset( + path: asset['path'], + flavors: (asset['flavors'] as YamlList?)?.toSet().cast() ?? {}, + ); } else { - assetName = asset as String; + tempAsset = FlavoredAsset(path: asset as String, flavors: {}); } - final assetAbsolutePath = join(rootPath, assetName); + final assetAbsolutePath = join(rootPath, tempAsset.path); if (FileSystemEntity.isDirectorySync(assetAbsolutePath)) { assetRelativePathList.addAll(Directory(assetAbsolutePath) .listSync() .whereType() - .map((e) => relative(e.path, from: rootPath)) + .map( + (e) => tempAsset.copyWith(path: relative(e.path, from: rootPath)), + ) .toList()); } else if (FileSystemEntity.isFileSync(assetAbsolutePath)) { - assetRelativePathList.add(relative(assetAbsolutePath, from: rootPath)); + assetRelativePathList.add( + tempAsset.copyWith(path: relative(assetAbsolutePath, from: rootPath)), + ); } } @@ -231,21 +241,25 @@ List _getAssetRelativePathList( } return assetRelativePathList - .where((file) => !excludes.any((exclude) => exclude.matches(file))) + .where((asset) => !excludes.any((exclude) => exclude.matches(asset.path))) .toList(); } AssetType _constructAssetTree( - List assetRelativePathList, String rootPath) { + List assetRelativePathList, + String rootPath, +) { // Relative path is the key final assetTypeMap = { - '.': AssetType(rootPath: rootPath, path: '.'), + '.': AssetType(rootPath: rootPath, path: '.', flavors: {}), }; - for (final assetPath in assetRelativePathList) { - var path = assetPath; + for (final asset in assetRelativePathList) { + String path = asset.path; while (path != '.') { assetTypeMap.putIfAbsent( - path, () => AssetType(rootPath: rootPath, path: path)); + path, + () => AssetType(rootPath: rootPath, path: path, flavors: asset.flavors), + ); path = dirname(path); } } @@ -327,7 +341,8 @@ String _dotDelimiterStyleDefinition( final assetsStaticStatements = <_Statement>[]; final assetTypeQueue = ListQueue.from( - _constructAssetTree(assetRelativePathList, rootPath).children); + _constructAssetTree(assetRelativePathList, rootPath).children, + ); while (assetTypeQueue.isNotEmpty) { final assetType = assetTypeQueue.removeFirst(); @@ -435,14 +450,20 @@ String _flatStyleDefinition( List integrations, String Function(String) style, ) { - final statements = _getAssetRelativePathList( + final paths = _getAssetRelativePathList( config.rootPath, config.assets, config.exclude, - ) - .distinct() - .sorted() - .map((assetPath) => AssetType(rootPath: config.rootPath, path: assetPath)) + ).toSet().toList(); + paths.sort(); + final statements = paths + .map( + (assetPath) => AssetType( + rootPath: config.rootPath, + path: assetPath.path, + flavors: assetPath.flavors, + ), + ) .mapToUniqueAssetType(style) .map( (e) => _createAssetTypeStatement( diff --git a/packages/core/lib/generators/integrations/flare_integration.dart b/packages/core/lib/generators/integrations/flare_integration.dart index db2b4dcc2..e8644e16f 100644 --- a/packages/core/lib/generators/integrations/flare_integration.dart +++ b/packages/core/lib/generators/integrations/flare_integration.dart @@ -17,9 +17,14 @@ class FlareIntegration extends Integration { String get classOutput => _classDefinition; String get _classDefinition => '''class FlareGenImage { - const FlareGenImage(this._assetName); + const FlareGenImage( + this._assetName, { + this.flavors = const {}, + }); final String _assetName; + final Set flavors; + ${isPackage ? "\n static const String package = '$packageName';" : ''} FlareActor flare({ @@ -63,10 +68,6 @@ ${isPackage ? "\n static const String package = '$packageName';" : ''} @override String get className => 'FlareGenImage'; - @override - String classInstantiate(AssetType asset) => - 'FlareGenImage(\'${asset.posixStylePath}\')'; - @override bool isSupport(AssetType asset) => asset.extension == '.flr'; diff --git a/packages/core/lib/generators/integrations/image_integration.dart b/packages/core/lib/generators/integrations/image_integration.dart index 672675786..17c71b561 100644 --- a/packages/core/lib/generators/integrations/image_integration.dart +++ b/packages/core/lib/generators/integrations/image_integration.dart @@ -10,8 +10,10 @@ import 'package:image_size_getter/image_size_getter.dart'; /// /// This integration is by enabled by default. class ImageIntegration extends Integration { - ImageIntegration(String packageName, {super.parseMetadata}) - : super(packageName); + ImageIntegration( + String packageName, { + super.parseMetadata, + }) : super(packageName); String get packageParameter => isPackage ? ' = package' : ''; @@ -25,12 +27,18 @@ class ImageIntegration extends Integration { String get classOutput => _classDefinition; String get _classDefinition => '''class AssetGenImage { - const AssetGenImage(this._assetName, {this.size = null}); + const AssetGenImage( + this._assetName, { + this.size, + this.flavors = const {}, + }); final String _assetName; + ${isPackage ? "\n static const String package = '$packageName';" : ''} final Size? size; + final Set flavors; Image image({ Key? key, @@ -109,11 +117,22 @@ ${isPackage ? "\n static const String package = '$packageName';" : ''} @override String classInstantiate(AssetType asset) { - ImageMetadata? info = parseMetadata ? _getMetadata(asset) : null; - - return 'AssetGenImage(\'${asset.posixStylePath}\'' - '${(info != null) ? ', size: Size(${info.width}, ${info.height})' : ''}' - ')'; + final info = parseMetadata ? _getMetadata(asset) : null; + final buffer = StringBuffer(className); + buffer.write('('); + buffer.write('\'${asset.posixStylePath}\''); + if (info != null) { + buffer.write(', size: Size(${info.width}, ${info.height})'); + } + if (asset.flavors.isNotEmpty) { + buffer.write(', flavors: {'); + final flavors = asset.flavors.map((e) => '\'$e\'').join(', '); + buffer.write(flavors); + buffer.write('}'); + buffer.write(','); // Better formatting. + } + buffer.write(')'); + return buffer.toString(); } @override diff --git a/packages/core/lib/generators/integrations/integration.dart b/packages/core/lib/generators/integrations/integration.dart index f4aa8bad8..4a32c713a 100644 --- a/packages/core/lib/generators/integrations/integration.dart +++ b/packages/core/lib/generators/integrations/integration.dart @@ -19,12 +19,25 @@ abstract class Integration { String get className; - String classInstantiate(AssetType asset); - /// Is this asset type supported by this integration? bool isSupport(AssetType asset); bool get isConstConstructor; + + String classInstantiate(AssetType asset) { + final buffer = StringBuffer(className); + buffer.write('('); + buffer.write('\'${asset.posixStylePath}\''); + if (asset.flavors.isNotEmpty) { + buffer.write(', flavors: {'); + final flavors = asset.flavors.map((e) => '\'$e\'').join(', '); + buffer.write(flavors); + buffer.write('}'); + buffer.write(','); // Better formatting. + } + buffer.write(')'); + return buffer.toString(); + } } /// The deprecation message for the package argument diff --git a/packages/core/lib/generators/integrations/lottie_integration.dart b/packages/core/lib/generators/integrations/lottie_integration.dart index 264153404..ac9bddd6e 100644 --- a/packages/core/lib/generators/integrations/lottie_integration.dart +++ b/packages/core/lib/generators/integrations/lottie_integration.dart @@ -32,9 +32,14 @@ class LottieIntegration extends Integration { String get classOutput => _classDefinition; String get _classDefinition => '''class LottieGenImage { - const LottieGenImage(this._assetName); + const LottieGenImage( + this._assetName, { + this.flavors = const {}, + }); final String _assetName; + final Set flavors; + ${isPackage ? "\n static const String package = '$packageName';" : ''} LottieBuilder lottie({ @@ -95,10 +100,6 @@ ${isPackage ? "\n static const String package = '$packageName';" : ''} @override String get className => 'LottieGenImage'; - @override - String classInstantiate(AssetType asset) => - 'LottieGenImage(\'${asset.posixStylePath}\')'; - @override bool isSupport(AssetType asset) => isLottieFile(asset); diff --git a/packages/core/lib/generators/integrations/rive_integration.dart b/packages/core/lib/generators/integrations/rive_integration.dart index 9830e4ff7..98742c54e 100644 --- a/packages/core/lib/generators/integrations/rive_integration.dart +++ b/packages/core/lib/generators/integrations/rive_integration.dart @@ -16,9 +16,14 @@ class RiveIntegration extends Integration { String get classOutput => _classDefinition; String get _classDefinition => '''class RiveGenImage { - const RiveGenImage(this._assetName); + const RiveGenImage( + this._assetName, { + this.flavors = const {}, + }); final String _assetName; + final Set flavors; + ${isPackage ? "\n static const String package = '$packageName';" : ''} RiveAnimation rive({ @@ -56,10 +61,6 @@ ${isPackage ? "\n static const String package = '$packageName';" : ''} @override String get className => 'RiveGenImage'; - @override - String classInstantiate(AssetType asset) => - 'RiveGenImage(\'${asset.posixStylePath}\')'; - @override bool isSupport(AssetType asset) => asset.extension == '.riv'; diff --git a/packages/core/lib/generators/integrations/svg_integration.dart b/packages/core/lib/generators/integrations/svg_integration.dart index 247afb1c9..1e21e1839 100644 --- a/packages/core/lib/generators/integrations/svg_integration.dart +++ b/packages/core/lib/generators/integrations/svg_integration.dart @@ -24,20 +24,23 @@ class SvgIntegration extends Integration { String get _classDefinition => '''class SvgGenImage { const SvgGenImage( this._assetName, { - this.size = null, + this.size, + this.flavors = const {}, }) : _isVecFormat = false; const SvgGenImage.vec( this._assetName, { - this.size = null, + this.size, + this.flavors = const {}, }) : _isVecFormat = true; final String _assetName; -${isPackage ? "\n static const String package = '$packageName';" : ''} - final Size? size; + final Set flavors; final bool _isVecFormat; +${isPackage ? "\n static const String package = '$packageName';" : ''} + SvgPicture svg({ Key? key, bool matchTextDirection = false, @@ -59,10 +62,23 @@ ${isPackage ? "\n static const String package = '$packageName';" : ''} @deprecated BlendMode colorBlendMode = BlendMode.srcIn, @deprecated bool cacheColorFilter = false, }) { + final BytesLoader loader; + if (_isVecFormat) { + loader = AssetBytesLoader( + _assetName, + assetBundle: bundle, + packageName: package, + ); + } else { + loader = SvgAssetLoader( + _assetName, + assetBundle: bundle, + packageName: package, + theme: theme, + ); + } return SvgPicture( - _isVecFormat ? - AssetBytesLoader(_assetName, assetBundle: bundle, packageName: package) : - SvgAssetLoader(_assetName, assetBundle: bundle, packageName: package, theme: theme), + loader, key: key, matchTextDirection: matchTextDirection, width: width, @@ -89,31 +105,42 @@ ${isPackage ? "\n static const String package = '$packageName';" : ''} @override String classInstantiate(AssetType asset) { - // Query extra information about the SVG - ImageMetadata? info = parseMetadata ? _getMetadata(asset) : null; - - final String constructorName = - asset.extension == '.vec' ? 'SvgGenImage.vec' : 'SvgGenImage'; - - return "$constructorName('${asset.posixStylePath}'" - "${(info != null) ? ', size: Size(${info.width}, ${info.height})' : ''}" - ')'; + // Query extra information about the SVG. + final info = parseMetadata ? _getMetadata(asset) : null; + final buffer = StringBuffer(className); + if (asset.extension == '.vec') { + buffer.write('.vec'); + } + buffer.write('('); + buffer.write('\'${asset.posixStylePath}\''); + if (info != null) { + buffer.write(', size: Size(${info.width}, ${info.height})'); + } + if (asset.flavors.isNotEmpty) { + buffer.write(', flavors: {'); + final flavors = asset.flavors.map((e) => '\'$e\'').join(', '); + buffer.write(flavors); + buffer.write('}'); + buffer.write(','); // Better formatting. + } + buffer.write(')'); + return buffer.toString(); } ImageMetadata? _getMetadata(AssetType asset) { try { // The SVG file is read fully, then parsed with the vector_graphics - // library. This is quite a heavy way to extract just the dimenions, but - // it's also the same way it will be eventually rendered by Flutter. + // library. This is quite a heavy way to extract just the dimensions, + // but it's also the same way it will be eventually rendered by Flutter. final svg = File(asset.fullPath).readAsStringSync(); final vec = parseWithoutOptimizers(svg); return ImageMetadata(vec.width, vec.height); } catch (e) { stderr.writeln( - '[WARNING] Failed to parse SVG \'${asset.path}\' metadata: $e'); + '[WARNING] Failed to parse SVG \'${asset.path}\' metadata: $e', + ); + return null; } - - return null; } @override diff --git a/packages/core/lib/settings/asset_type.dart b/packages/core/lib/settings/asset_type.dart index 0f682c034..3c2fee972 100644 --- a/packages/core/lib/settings/asset_type.dart +++ b/packages/core/lib/settings/asset_type.dart @@ -7,10 +7,15 @@ import 'package:path/path.dart'; /// https://github.com/dart-lang/mime/blob/master/lib/src/default_extension_map.dart class AssetType { - AssetType({required this.rootPath, required this.path}); + AssetType({ + required this.rootPath, + required this.path, + required this.flavors, + }); final String rootPath; final String path; + final Set flavors; final List _children = List.empty(growable: true); @@ -68,7 +73,11 @@ class UniqueAssetType extends AssetType { this.basenameOnly = false, this.needExtension = false, this.suffix = '', - }) : super(rootPath: assetType.rootPath, path: assetType.path); + }) : super( + rootPath: assetType.rootPath, + path: assetType.path, + flavors: assetType.flavors, + ); /// Convert the asset name to a correctly styled name, e.g camelCase or /// snakeCase. diff --git a/packages/core/lib/settings/flavored_asset.dart b/packages/core/lib/settings/flavored_asset.dart new file mode 100644 index 000000000..8769e3601 --- /dev/null +++ b/packages/core/lib/settings/flavored_asset.dart @@ -0,0 +1,16 @@ +class FlavoredAsset { + const FlavoredAsset({ + required this.path, + required this.flavors, + }); + + final String path; + final Set flavors; + + FlavoredAsset copyWith({String? path, Set? flavors}) { + return FlavoredAsset( + path: path ?? this.path, + flavors: flavors ?? this.flavors, + ); + } +} From 2761b4c0336495dc17e114a33562a613f972ec0e Mon Sep 17 00:00:00 2001 From: Alex Li Date: Mon, 17 Jun 2024 22:25:22 +0800 Subject: [PATCH 03/14] =?UTF-8?q?=E2=9C=85=20Fix=20internal=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../test/assets_gen_integrations_test.dart | 140 +++++++++++++----- packages/core/test/assets_gen_test.dart | 25 ++-- 2 files changed, 121 insertions(+), 44 deletions(-) diff --git a/packages/core/test/assets_gen_integrations_test.dart b/packages/core/test/assets_gen_integrations_test.dart index 3fc67a039..f9637f141 100644 --- a/packages/core/test/assets_gen_integrations_test.dart +++ b/packages/core/test/assets_gen_integrations_test.dart @@ -34,17 +34,34 @@ void main() { expect(integration.className, 'SvgGenImage'); expect( integration.classInstantiate( - AssetType(rootPath: resPath, path: 'assets/path')), + AssetType( + rootPath: resPath, + path: 'assets/path', + flavors: {}, + ), + ), 'SvgGenImage(\'assets/path\')', ); expect( - integration.isSupport( - AssetType(rootPath: resPath, path: 'assets/path/dog.svg')), - isTrue); + integration.isSupport( + AssetType( + rootPath: resPath, + path: 'assets/path/dog.svg', + flavors: {}, + ), + ), + isTrue, + ); expect( - integration.isSupport( - AssetType(rootPath: resPath, path: 'assets/path/dog.png')), - isFalse); + integration.isSupport( + AssetType( + rootPath: resPath, + path: 'assets/path/dog.png', + flavors: {}, + ), + ), + isFalse, + ); expect(integration.isConstConstructor, isTrue); expect(integration.classOutput.contains('String? package,'), isTrue); @@ -75,17 +92,35 @@ void main() { final integration = FlareIntegration(''); expect(integration.className, 'FlareGenImage'); expect( - integration.classInstantiate( - AssetType(rootPath: resPath, path: 'assets/path')), - 'FlareGenImage(\'assets/path\')'); + integration.classInstantiate( + AssetType( + rootPath: resPath, + path: 'assets/path', + flavors: {}, + ), + ), + 'FlareGenImage(\'assets/path\')', + ); expect( - integration.isSupport( - AssetType(rootPath: resPath, path: 'assets/path/dog.flr')), - isTrue); + integration.isSupport( + AssetType( + rootPath: resPath, + path: 'assets/path/dog.flr', + flavors: {}, + ), + ), + isTrue, + ); expect( - integration.isSupport( - AssetType(rootPath: resPath, path: 'assets/path/dog.json')), - isFalse); + integration.isSupport( + AssetType( + rootPath: resPath, + path: 'assets/path/dog.json', + flavors: {}, + ), + ), + isFalse, + ); expect(integration.isConstConstructor, isTrue); expect(integration.classOutput.contains('_assetName,'), isTrue); @@ -109,17 +144,35 @@ void main() { final integration = RiveIntegration(''); expect(integration.className, 'RiveGenImage'); expect( - integration.classInstantiate( - AssetType(rootPath: resPath, path: 'assets/path')), - 'RiveGenImage(\'assets/path\')'); + integration.classInstantiate( + AssetType( + rootPath: resPath, + path: 'assets/path', + flavors: {}, + ), + ), + 'RiveGenImage(\'assets/path\')', + ); expect( - integration.isSupport( - AssetType(rootPath: resPath, path: 'assets/path/dog.riv')), - isTrue); + integration.isSupport( + AssetType( + rootPath: resPath, + path: 'assets/path/dog.riv', + flavors: {}, + ), + ), + isTrue, + ); expect( - integration.isSupport( - AssetType(rootPath: resPath, path: 'assets/path/dog.json')), - isFalse); + integration.isSupport( + AssetType( + rootPath: resPath, + path: 'assets/path/dog.json', + flavors: {}, + ), + ), + isFalse, + ); expect(integration.isConstConstructor, isTrue); expect(integration.classOutput.contains('_assetName,'), isTrue); @@ -143,18 +196,35 @@ void main() { final integration = LottieIntegration(''); expect(integration.className, 'LottieGenImage'); expect( - integration.classInstantiate( - AssetType(rootPath: resPath, path: 'assets/lottie')), - 'LottieGenImage(\'assets/lottie\')'); + integration.classInstantiate( + AssetType( + rootPath: resPath, + path: 'assets/lottie', + flavors: {}, + ), + ), + 'LottieGenImage(\'assets/lottie\')', + ); expect( - integration.isSupport(AssetType( - rootPath: resPath, path: 'assets/lottie/hamburger_arrow.json')), - isTrue); + integration.isSupport( + AssetType( + rootPath: resPath, + path: 'assets/lottie/hamburger_arrow.json', + flavors: {}, + ), + ), + isTrue, + ); expect( - integration.isSupport(AssetType( - rootPath: resPath, - path: 'assets/lottie/hamburger_arrow_without_version.json')), - isFalse); + integration.isSupport( + AssetType( + rootPath: resPath, + path: 'assets/lottie/hamburger_arrow_without_version.json', + flavors: {}, + ), + ), + isFalse, + ); expect(integration.isConstConstructor, isTrue); expect(integration.classOutput.contains('String? package,'), isTrue); diff --git a/packages/core/test/assets_gen_test.dart b/packages/core/test/assets_gen_test.dart index 4f3315d22..826ed271f 100644 --- a/packages/core/test/assets_gen_test.dart +++ b/packages/core/test/assets_gen_test.dart @@ -143,7 +143,8 @@ void main() { 'assets/profilePng.jpg': 'profilePngJpg', // Asset overlapping with a directory name. - 'assets/image': 'image', // Directory + 'assets/image': 'image', + // Directory 'assets/image.jpg': 'imageJpg', // Asset with no base name (but ends up overlapping the previous asset) @@ -155,12 +156,18 @@ void main() { 'assets/français.jpg': 'franAis', // Dart Reserved Words - 'assets/async.png': 'async', // allowed - 'assets/abstract.png': 'abstract', // allowed - 'assets/await.png': 'awaitPng', // must be suffixed (but can use Png) - 'assets/assert.png': 'assertPng', // must be suffixed (but can use Png) - 'assets/await': 'await_', // must be suffixed - 'assets/assert': 'assert_', // must be suffixed + 'assets/async.png': 'async', + // allowed + 'assets/abstract.png': 'abstract', + // allowed + 'assets/await.png': 'awaitPng', + // must be suffixed (but can use Png) + 'assets/assert.png': 'assertPng', + // must be suffixed (but can use Png) + 'assets/await': 'await_', + // must be suffixed + 'assets/assert': 'assert_', + // must be suffixed // Asset with a number as the first character 'assets/7up.png': 'a7up', @@ -176,12 +183,12 @@ void main() { final List assets = tests.keys .sorted() - .map((e) => AssetType(rootPath: '', path: e)) + .map((e) => AssetType(rootPath: '', path: e, flavors: {})) .toList(); final got = assets.mapToUniqueAssetType(camelCase); - // Expect no dups. + // Expect no duplicates. final names = got.map((e) => e.name); expect(names.sorted(), tests.values.sorted()); }); From ec6347eef6d65a180c281d81b48898d404563a0b Mon Sep 17 00:00:00 2001 From: Alex Li Date: Tue, 18 Jun 2024 00:17:43 +0800 Subject: [PATCH 04/14] =?UTF-8?q?=F0=9F=90=9B=20Normalize?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/lib/generators/assets_generator.dart | 39 ++++++++++++++----- .../core/lib/settings/flavored_asset.dart | 5 ++- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/packages/core/lib/generators/assets_generator.dart b/packages/core/lib/generators/assets_generator.dart index c727e87e7..2547f0d48 100644 --- a/packages/core/lib/generators/assets_generator.dart +++ b/packages/core/lib/generators/assets_generator.dart @@ -209,16 +209,36 @@ List _getAssetRelativePathList( /// section in the pubspec.yaml. List excludes, ) { + // Normalize. + final normalizedAssets = {...assets.whereType()}; + final normalizingMap = >{}; + // Resolve flavored assets. + for (final map in assets.whereType()) { + final path = (map['path'] as String).trim(); + final flavors = + (map['flavors'] as YamlList?)?.toSet().cast() ?? {}; + if (normalizingMap.containsKey(path)) { + // https://github.com/flutter/flutter/blob/5187cab7bdd434ca74abb45895d17e9fa553678a/packages/flutter_tools/lib/src/asset.dart#L1137-L1139 + throw StateError( + 'Multiple assets entries include the file "$path", ' + 'but they specify different lists of flavors.', + ); + } + normalizingMap[path] = flavors; + } + for (final entry in normalizingMap.entries) { + normalizedAssets.add( + YamlMap.wrap({'path': entry.key, 'flavors': entry.value}), + ); + } + final assetRelativePathList = []; - for (final asset in assets) { + for (final asset in normalizedAssets) { final FlavoredAsset tempAsset; if (asset is YamlMap) { - tempAsset = FlavoredAsset( - path: asset['path'], - flavors: (asset['flavors'] as YamlList?)?.toSet().cast() ?? {}, - ); + tempAsset = FlavoredAsset(path: asset['path'], flavors: asset['flavors']); } else { - tempAsset = FlavoredAsset(path: asset as String, flavors: {}); + tempAsset = FlavoredAsset(path: (asset as String).trim()); } final assetAbsolutePath = join(rootPath, tempAsset.path); if (FileSystemEntity.isDirectorySync(assetAbsolutePath)) { @@ -239,7 +259,6 @@ List _getAssetRelativePathList( if (excludes.isEmpty) { return assetRelativePathList; } - return assetRelativePathList .where((asset) => !excludes.any((exclude) => exclude.matches(asset.path))) .toList(); @@ -450,12 +469,12 @@ String _flatStyleDefinition( List integrations, String Function(String) style, ) { - final paths = _getAssetRelativePathList( + final List paths = _getAssetRelativePathList( config.rootPath, config.assets, config.exclude, - ).toSet().toList(); - paths.sort(); + ); + paths.sort(((a, b) => a.path.compareTo(b.path))); final statements = paths .map( (assetPath) => AssetType( diff --git a/packages/core/lib/settings/flavored_asset.dart b/packages/core/lib/settings/flavored_asset.dart index 8769e3601..66e24aa03 100644 --- a/packages/core/lib/settings/flavored_asset.dart +++ b/packages/core/lib/settings/flavored_asset.dart @@ -1,7 +1,7 @@ class FlavoredAsset { const FlavoredAsset({ required this.path, - required this.flavors, + this.flavors = const {}, }); final String path; @@ -13,4 +13,7 @@ class FlavoredAsset { flavors: flavors ?? this.flavors, ); } + + @override + String toString() => 'FlavoredAsset(path: $path, flavors: $flavors)'; } From a164a59447027e11228abdd903155179a9ecfa8a Mon Sep 17 00:00:00 2001 From: Alex Li Date: Tue, 18 Jun 2024 00:18:04 +0800 Subject: [PATCH 05/14] =?UTF-8?q?=F0=9F=9A=80=20Update=20the=20example?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/example/lib/gen/assets.gen.dart | 74 +++++++++++++++++++----- examples/example/pubspec.yaml | 1 - 2 files changed, 60 insertions(+), 15 deletions(-) diff --git a/examples/example/lib/gen/assets.gen.dart b/examples/example/lib/gen/assets.gen.dart index 9efacf68d..8a740f6e8 100644 --- a/examples/example/lib/gen/assets.gen.dart +++ b/examples/example/lib/gen/assets.gen.dart @@ -35,6 +35,9 @@ class $AssetsImagesGen { /// File path: assets/images/chip2.jpg AssetGenImage get chip2 => const AssetGenImage('assets/images/chip2.jpg'); + /// Directory path: assets/images/chip3 + $AssetsImagesChip3Gen get chip3 => const $AssetsImagesChip3Gen(); + /// Directory path: assets/images/chip4 $AssetsImagesChip4Gen get chip4 => const $AssetsImagesChip4Gen(); @@ -142,12 +145,25 @@ class $AssetsUnknownGen { List get values => [changelog, readme, unknownMimeType]; } +class $AssetsImagesChip3Gen { + const $AssetsImagesChip3Gen(); + + /// File path: assets/images/chip3/chip3.jpg + AssetGenImage get chip3 => + const AssetGenImage('assets/images/chip3/chip3.jpg'); + + /// List of all assets + List get values => [chip3]; +} + class $AssetsImagesChip4Gen { const $AssetsImagesChip4Gen(); /// File path: assets/images/chip4/chip4.jpg - AssetGenImage get chip4 => - const AssetGenImage('assets/images/chip4/chip4.jpg'); + AssetGenImage get chip4 => const AssetGenImage( + 'assets/images/chip4/chip4.jpg', + flavors: {'extern'}, + ); /// List of all assets List get values => [chip4]; @@ -202,11 +218,16 @@ class MyAssets { } class AssetGenImage { - const AssetGenImage(this._assetName, {this.size = null}); + const AssetGenImage( + this._assetName, { + this.size, + this.flavors = const {}, + }); final String _assetName; final Size? size; + final Set flavors; Image image({ Key? key, @@ -280,17 +301,19 @@ class AssetGenImage { class SvgGenImage { const SvgGenImage( this._assetName, { - this.size = null, + this.size, + this.flavors = const {}, }) : _isVecFormat = false; const SvgGenImage.vec( this._assetName, { - this.size = null, + this.size, + this.flavors = const {}, }) : _isVecFormat = true; final String _assetName; - final Size? size; + final Set flavors; final bool _isVecFormat; SvgPicture svg({ @@ -313,12 +336,22 @@ class SvgGenImage { @deprecated BlendMode colorBlendMode = BlendMode.srcIn, @deprecated bool cacheColorFilter = false, }) { + final BytesLoader loader; + if (_isVecFormat) { + loader = AssetBytesLoader( + _assetName, + assetBundle: bundle, + packageName: package, + ); + } else { + loader = SvgAssetLoader( + _assetName, + assetBundle: bundle, + packageName: package, + ); + } return SvgPicture( - _isVecFormat - ? AssetBytesLoader(_assetName, - assetBundle: bundle, packageName: package) - : SvgAssetLoader(_assetName, - assetBundle: bundle, packageName: package, theme: theme), + loader, key: key, matchTextDirection: matchTextDirection, width: width, @@ -329,6 +362,7 @@ class SvgGenImage { placeholderBuilder: placeholderBuilder, semanticsLabel: semanticsLabel, excludeFromSemantics: excludeFromSemantics, + theme: theme, colorFilter: colorFilter ?? (color == null ? null : ColorFilter.mode(color, colorBlendMode)), clipBehavior: clipBehavior, @@ -342,9 +376,13 @@ class SvgGenImage { } class FlareGenImage { - const FlareGenImage(this._assetName); + const FlareGenImage( + this._assetName, { + this.flavors = const {}, + }); final String _assetName; + final Set flavors; FlareActor flare({ String? boundsNode, @@ -385,9 +423,13 @@ class FlareGenImage { } class RiveGenImage { - const RiveGenImage(this._assetName); + const RiveGenImage( + this._assetName, { + this.flavors = const {}, + }); final String _assetName; + final Set flavors; RiveAnimation rive({ String? artboard, @@ -422,9 +464,13 @@ class RiveGenImage { } class LottieGenImage { - const LottieGenImage(this._assetName); + const LottieGenImage( + this._assetName, { + this.flavors = const {}, + }); final String _assetName; + final Set flavors; LottieBuilder lottie({ Animation? controller, diff --git a/examples/example/pubspec.yaml b/examples/example/pubspec.yaml index 411f14017..4e92cb1d8 100644 --- a/examples/example/pubspec.yaml +++ b/examples/example/pubspec.yaml @@ -51,7 +51,6 @@ flutter_gen: style: dot-delimiter exclude: - - assets/images/chip3/chip3.jpg - assets-extern/* - pictures/chip5.jpg From d020b54f7a9e1a37c2bfecf1d21f2883c1f3caed Mon Sep 17 00:00:00 2001 From: Alex Li Date: Tue, 18 Jun 2024 00:18:25 +0800 Subject: [PATCH 06/14] =?UTF-8?q?=F0=9F=9A=9A=20Update=20test=20resources?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../actual_data/assets.gen.dart | 42 ++++++++++++++----- .../actual_data/assets_camel_case.gen.dart | 7 +++- .../assets_change_class_name.gen.dart | 7 +++- .../assets_directory_path.gen.dart | 36 ++++++++++++---- .../assets_flare_integrations.gen.dart | 6 ++- .../assets_lottie_integrations.gen.dart | 6 ++- .../assets_no_integrations.gen.dart | 7 +++- .../assets_package_exclude_files.gen.dart | 7 +++- .../assets_package_parameter.gen.dart | 40 +++++++++++++----- .../assets_parse_metadata.gen.dart | 42 ++++++++++++++----- .../assets_rive_integrations.gen.dart | 6 ++- .../actual_data/assets_snake_case.gen.dart | 7 +++- .../assets_svg_integrations.gen.dart | 29 +++++++++---- 13 files changed, 186 insertions(+), 56 deletions(-) diff --git a/packages/core/test_resources/actual_data/assets.gen.dart b/packages/core/test_resources/actual_data/assets.gen.dart index 623750cb5..d543ae110 100644 --- a/packages/core/test_resources/actual_data/assets.gen.dart +++ b/packages/core/test_resources/actual_data/assets.gen.dart @@ -160,11 +160,16 @@ class Assets { } class AssetGenImage { - const AssetGenImage(this._assetName, {this.size = null}); + const AssetGenImage( + this._assetName, { + this.size, + this.flavors = const {}, + }); final String _assetName; final Size? size; + final Set flavors; Image image({ Key? key, @@ -238,17 +243,19 @@ class AssetGenImage { class SvgGenImage { const SvgGenImage( this._assetName, { - this.size = null, + this.size, + this.flavors = const {}, }) : _isVecFormat = false; const SvgGenImage.vec( this._assetName, { - this.size = null, + this.size, + this.flavors = const {}, }) : _isVecFormat = true; final String _assetName; - final Size? size; + final Set flavors; final bool _isVecFormat; SvgPicture svg({ @@ -271,12 +278,22 @@ class SvgGenImage { @deprecated BlendMode colorBlendMode = BlendMode.srcIn, @deprecated bool cacheColorFilter = false, }) { + final BytesLoader loader; + if (_isVecFormat) { + loader = AssetBytesLoader( + _assetName, + assetBundle: bundle, + packageName: package, + ); + } else { + loader = SvgAssetLoader( + _assetName, + assetBundle: bundle, + packageName: package, + ); + } return SvgPicture( - _isVecFormat - ? AssetBytesLoader(_assetName, - assetBundle: bundle, packageName: package) - : SvgAssetLoader(_assetName, - assetBundle: bundle, packageName: package, theme: theme), + loader, key: key, matchTextDirection: matchTextDirection, width: width, @@ -287,6 +304,7 @@ class SvgGenImage { placeholderBuilder: placeholderBuilder, semanticsLabel: semanticsLabel, excludeFromSemantics: excludeFromSemantics, + theme: theme, colorFilter: colorFilter ?? (color == null ? null : ColorFilter.mode(color, colorBlendMode)), clipBehavior: clipBehavior, @@ -300,9 +318,13 @@ class SvgGenImage { } class FlareGenImage { - const FlareGenImage(this._assetName); + const FlareGenImage( + this._assetName, { + this.flavors = const {}, + }); final String _assetName; + final Set flavors; FlareActor flare({ String? boundsNode, diff --git a/packages/core/test_resources/actual_data/assets_camel_case.gen.dart b/packages/core/test_resources/actual_data/assets_camel_case.gen.dart index 95df6265c..f409e1043 100644 --- a/packages/core/test_resources/actual_data/assets_camel_case.gen.dart +++ b/packages/core/test_resources/actual_data/assets_camel_case.gen.dart @@ -82,11 +82,16 @@ class Assets { } class AssetGenImage { - const AssetGenImage(this._assetName, {this.size = null}); + const AssetGenImage( + this._assetName, { + this.size, + this.flavors = const {}, + }); final String _assetName; final Size? size; + final Set flavors; Image image({ Key? key, diff --git a/packages/core/test_resources/actual_data/assets_change_class_name.gen.dart b/packages/core/test_resources/actual_data/assets_change_class_name.gen.dart index e73d70e0a..36f01d714 100644 --- a/packages/core/test_resources/actual_data/assets_change_class_name.gen.dart +++ b/packages/core/test_resources/actual_data/assets_change_class_name.gen.dart @@ -41,11 +41,16 @@ class MyAssets { } class AssetGenImage { - const AssetGenImage(this._assetName, {this.size = null}); + const AssetGenImage( + this._assetName, { + this.size, + this.flavors = const {}, + }); final String _assetName; final Size? size; + final Set flavors; Image image({ Key? key, diff --git a/packages/core/test_resources/actual_data/assets_directory_path.gen.dart b/packages/core/test_resources/actual_data/assets_directory_path.gen.dart index 0071ab5d1..a68bf81fb 100644 --- a/packages/core/test_resources/actual_data/assets_directory_path.gen.dart +++ b/packages/core/test_resources/actual_data/assets_directory_path.gen.dart @@ -78,11 +78,16 @@ class Assets { } class AssetGenImage { - const AssetGenImage(this._assetName, {this.size = null}); + const AssetGenImage( + this._assetName, { + this.size, + this.flavors = const {}, + }); final String _assetName; final Size? size; + final Set flavors; Image image({ Key? key, @@ -156,17 +161,19 @@ class AssetGenImage { class SvgGenImage { const SvgGenImage( this._assetName, { - this.size = null, + this.size, + this.flavors = const {}, }) : _isVecFormat = false; const SvgGenImage.vec( this._assetName, { - this.size = null, + this.size, + this.flavors = const {}, }) : _isVecFormat = true; final String _assetName; - final Size? size; + final Set flavors; final bool _isVecFormat; SvgPicture svg({ @@ -189,12 +196,22 @@ class SvgGenImage { @deprecated BlendMode colorBlendMode = BlendMode.srcIn, @deprecated bool cacheColorFilter = false, }) { + final BytesLoader loader; + if (_isVecFormat) { + loader = AssetBytesLoader( + _assetName, + assetBundle: bundle, + packageName: package, + ); + } else { + loader = SvgAssetLoader( + _assetName, + assetBundle: bundle, + packageName: package, + ); + } return SvgPicture( - _isVecFormat - ? AssetBytesLoader(_assetName, - assetBundle: bundle, packageName: package) - : SvgAssetLoader(_assetName, - assetBundle: bundle, packageName: package, theme: theme), + loader, key: key, matchTextDirection: matchTextDirection, width: width, @@ -205,6 +222,7 @@ class SvgGenImage { placeholderBuilder: placeholderBuilder, semanticsLabel: semanticsLabel, excludeFromSemantics: excludeFromSemantics, + theme: theme, colorFilter: colorFilter ?? (color == null ? null : ColorFilter.mode(color, colorBlendMode)), clipBehavior: clipBehavior, diff --git a/packages/core/test_resources/actual_data/assets_flare_integrations.gen.dart b/packages/core/test_resources/actual_data/assets_flare_integrations.gen.dart index 231614e7c..02b53db94 100644 --- a/packages/core/test_resources/actual_data/assets_flare_integrations.gen.dart +++ b/packages/core/test_resources/actual_data/assets_flare_integrations.gen.dart @@ -28,9 +28,13 @@ class Assets { } class FlareGenImage { - const FlareGenImage(this._assetName); + const FlareGenImage( + this._assetName, { + this.flavors = const {}, + }); final String _assetName; + final Set flavors; FlareActor flare({ String? boundsNode, diff --git a/packages/core/test_resources/actual_data/assets_lottie_integrations.gen.dart b/packages/core/test_resources/actual_data/assets_lottie_integrations.gen.dart index abde7ee96..8db51bf65 100644 --- a/packages/core/test_resources/actual_data/assets_lottie_integrations.gen.dart +++ b/packages/core/test_resources/actual_data/assets_lottie_integrations.gen.dart @@ -28,9 +28,13 @@ class Assets { } class LottieGenImage { - const LottieGenImage(this._assetName); + const LottieGenImage( + this._assetName, { + this.flavors = const {}, + }); final String _assetName; + final Set flavors; LottieBuilder lottie({ Animation? controller, diff --git a/packages/core/test_resources/actual_data/assets_no_integrations.gen.dart b/packages/core/test_resources/actual_data/assets_no_integrations.gen.dart index 722ecdc7c..8774a22cb 100644 --- a/packages/core/test_resources/actual_data/assets_no_integrations.gen.dart +++ b/packages/core/test_resources/actual_data/assets_no_integrations.gen.dart @@ -116,11 +116,16 @@ class Assets { } class AssetGenImage { - const AssetGenImage(this._assetName, {this.size = null}); + const AssetGenImage( + this._assetName, { + this.size, + this.flavors = const {}, + }); final String _assetName; final Size? size; + final Set flavors; Image image({ Key? key, diff --git a/packages/core/test_resources/actual_data/assets_package_exclude_files.gen.dart b/packages/core/test_resources/actual_data/assets_package_exclude_files.gen.dart index d60634822..e67908c7e 100644 --- a/packages/core/test_resources/actual_data/assets_package_exclude_files.gen.dart +++ b/packages/core/test_resources/actual_data/assets_package_exclude_files.gen.dart @@ -71,11 +71,16 @@ class Assets { } class AssetGenImage { - const AssetGenImage(this._assetName, {this.size = null}); + const AssetGenImage( + this._assetName, { + this.size, + this.flavors = const {}, + }); final String _assetName; final Size? size; + final Set flavors; Image image({ Key? key, diff --git a/packages/core/test_resources/actual_data/assets_package_parameter.gen.dart b/packages/core/test_resources/actual_data/assets_package_parameter.gen.dart index 99ae52686..04cdf5f70 100644 --- a/packages/core/test_resources/actual_data/assets_package_parameter.gen.dart +++ b/packages/core/test_resources/actual_data/assets_package_parameter.gen.dart @@ -69,13 +69,18 @@ class Assets { } class AssetGenImage { - const AssetGenImage(this._assetName, {this.size = null}); + const AssetGenImage( + this._assetName, { + this.size, + this.flavors = const {}, + }); final String _assetName; static const String package = 'test'; final Size? size; + final Set flavors; Image image({ Key? key, @@ -151,21 +156,23 @@ class AssetGenImage { class SvgGenImage { const SvgGenImage( this._assetName, { - this.size = null, + this.size, + this.flavors = const {}, }) : _isVecFormat = false; const SvgGenImage.vec( this._assetName, { - this.size = null, + this.size, + this.flavors = const {}, }) : _isVecFormat = true; final String _assetName; - - static const String package = 'test'; - final Size? size; + final Set flavors; final bool _isVecFormat; + static const String package = 'test'; + SvgPicture svg({ Key? key, bool matchTextDirection = false, @@ -187,12 +194,22 @@ class SvgGenImage { @deprecated BlendMode colorBlendMode = BlendMode.srcIn, @deprecated bool cacheColorFilter = false, }) { + final BytesLoader loader; + if (_isVecFormat) { + loader = AssetBytesLoader( + _assetName, + assetBundle: bundle, + packageName: package, + ); + } else { + loader = SvgAssetLoader( + _assetName, + assetBundle: bundle, + packageName: package, + ); + } return SvgPicture( - _isVecFormat - ? AssetBytesLoader(_assetName, - assetBundle: bundle, packageName: package) - : SvgAssetLoader(_assetName, - assetBundle: bundle, packageName: package, theme: theme), + loader, key: key, matchTextDirection: matchTextDirection, width: width, @@ -203,6 +220,7 @@ class SvgGenImage { placeholderBuilder: placeholderBuilder, semanticsLabel: semanticsLabel, excludeFromSemantics: excludeFromSemantics, + theme: theme, colorFilter: colorFilter ?? (color == null ? null : ColorFilter.mode(color, colorBlendMode)), clipBehavior: clipBehavior, diff --git a/packages/core/test_resources/actual_data/assets_parse_metadata.gen.dart b/packages/core/test_resources/actual_data/assets_parse_metadata.gen.dart index 8a343ff4b..36b275c7c 100644 --- a/packages/core/test_resources/actual_data/assets_parse_metadata.gen.dart +++ b/packages/core/test_resources/actual_data/assets_parse_metadata.gen.dart @@ -169,11 +169,16 @@ class Assets { } class AssetGenImage { - const AssetGenImage(this._assetName, {this.size = null}); + const AssetGenImage( + this._assetName, { + this.size, + this.flavors = const {}, + }); final String _assetName; final Size? size; + final Set flavors; Image image({ Key? key, @@ -247,17 +252,19 @@ class AssetGenImage { class SvgGenImage { const SvgGenImage( this._assetName, { - this.size = null, + this.size, + this.flavors = const {}, }) : _isVecFormat = false; const SvgGenImage.vec( this._assetName, { - this.size = null, + this.size, + this.flavors = const {}, }) : _isVecFormat = true; final String _assetName; - final Size? size; + final Set flavors; final bool _isVecFormat; SvgPicture svg({ @@ -280,12 +287,22 @@ class SvgGenImage { @deprecated BlendMode colorBlendMode = BlendMode.srcIn, @deprecated bool cacheColorFilter = false, }) { + final BytesLoader loader; + if (_isVecFormat) { + loader = AssetBytesLoader( + _assetName, + assetBundle: bundle, + packageName: package, + ); + } else { + loader = SvgAssetLoader( + _assetName, + assetBundle: bundle, + packageName: package, + ); + } return SvgPicture( - _isVecFormat - ? AssetBytesLoader(_assetName, - assetBundle: bundle, packageName: package) - : SvgAssetLoader(_assetName, - assetBundle: bundle, packageName: package, theme: theme), + loader, key: key, matchTextDirection: matchTextDirection, width: width, @@ -296,6 +313,7 @@ class SvgGenImage { placeholderBuilder: placeholderBuilder, semanticsLabel: semanticsLabel, excludeFromSemantics: excludeFromSemantics, + theme: theme, colorFilter: colorFilter ?? (color == null ? null : ColorFilter.mode(color, colorBlendMode)), clipBehavior: clipBehavior, @@ -309,9 +327,13 @@ class SvgGenImage { } class FlareGenImage { - const FlareGenImage(this._assetName); + const FlareGenImage( + this._assetName, { + this.flavors = const {}, + }); final String _assetName; + final Set flavors; FlareActor flare({ String? boundsNode, diff --git a/packages/core/test_resources/actual_data/assets_rive_integrations.gen.dart b/packages/core/test_resources/actual_data/assets_rive_integrations.gen.dart index 54841081b..d296b1689 100644 --- a/packages/core/test_resources/actual_data/assets_rive_integrations.gen.dart +++ b/packages/core/test_resources/actual_data/assets_rive_integrations.gen.dart @@ -27,9 +27,13 @@ class Assets { } class RiveGenImage { - const RiveGenImage(this._assetName); + const RiveGenImage( + this._assetName, { + this.flavors = const {}, + }); final String _assetName; + final Set flavors; RiveAnimation rive({ String? artboard, diff --git a/packages/core/test_resources/actual_data/assets_snake_case.gen.dart b/packages/core/test_resources/actual_data/assets_snake_case.gen.dart index 07baa9ccc..31d813ae0 100644 --- a/packages/core/test_resources/actual_data/assets_snake_case.gen.dart +++ b/packages/core/test_resources/actual_data/assets_snake_case.gen.dart @@ -83,11 +83,16 @@ class Assets { } class AssetGenImage { - const AssetGenImage(this._assetName, {this.size = null}); + const AssetGenImage( + this._assetName, { + this.size, + this.flavors = const {}, + }); final String _assetName; final Size? size; + final Set flavors; Image image({ Key? key, diff --git a/packages/core/test_resources/actual_data/assets_svg_integrations.gen.dart b/packages/core/test_resources/actual_data/assets_svg_integrations.gen.dart index 4d9b32b11..88ddd5b1e 100644 --- a/packages/core/test_resources/actual_data/assets_svg_integrations.gen.dart +++ b/packages/core/test_resources/actual_data/assets_svg_integrations.gen.dart @@ -43,17 +43,19 @@ class Assets { class SvgGenImage { const SvgGenImage( this._assetName, { - this.size = null, + this.size, + this.flavors = const {}, }) : _isVecFormat = false; const SvgGenImage.vec( this._assetName, { - this.size = null, + this.size, + this.flavors = const {}, }) : _isVecFormat = true; final String _assetName; - final Size? size; + final Set flavors; final bool _isVecFormat; SvgPicture svg({ @@ -76,12 +78,22 @@ class SvgGenImage { @deprecated BlendMode colorBlendMode = BlendMode.srcIn, @deprecated bool cacheColorFilter = false, }) { + final BytesLoader loader; + if (_isVecFormat) { + loader = AssetBytesLoader( + _assetName, + assetBundle: bundle, + packageName: package, + ); + } else { + loader = SvgAssetLoader( + _assetName, + assetBundle: bundle, + packageName: package, + ); + } return SvgPicture( - _isVecFormat - ? AssetBytesLoader(_assetName, - assetBundle: bundle, packageName: package) - : SvgAssetLoader(_assetName, - assetBundle: bundle, packageName: package, theme: theme), + loader, key: key, matchTextDirection: matchTextDirection, width: width, @@ -92,6 +104,7 @@ class SvgGenImage { placeholderBuilder: placeholderBuilder, semanticsLabel: semanticsLabel, excludeFromSemantics: excludeFromSemantics, + theme: theme, colorFilter: colorFilter ?? (color == null ? null : ColorFilter.mode(color, colorBlendMode)), clipBehavior: clipBehavior, From e3bb7b9700b67cd920392a16f4f88d342b71d8bf Mon Sep 17 00:00:00 2001 From: Alex Li Date: Tue, 18 Jun 2024 00:36:39 +0800 Subject: [PATCH 07/14] =?UTF-8?q?=F0=9F=90=9B=20Fix=20runner?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/runner/lib/flutter_gen_runner.dart | 26 ++++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/packages/runner/lib/flutter_gen_runner.dart b/packages/runner/lib/flutter_gen_runner.dart index 03ab755b5..47c085fdb 100644 --- a/packages/runner/lib/flutter_gen_runner.dart +++ b/packages/runner/lib/flutter_gen_runner.dart @@ -6,6 +6,7 @@ import 'package:collection/collection.dart'; import 'package:crypto/crypto.dart'; import 'package:flutter_gen_core/flutter_generator.dart'; import 'package:flutter_gen_core/settings/config.dart'; +import 'package:flutter_gen_core/settings/flavored_asset.dart'; import 'package:glob/glob.dart'; import 'package:path/path.dart'; import 'package:yaml/yaml.dart'; @@ -61,14 +62,21 @@ class FlutterGenBuilder extends Builder { ) async { final pubspec = config.pubspec; - final HashSet assets = HashSet(); + final HashSet assets = HashSet(); if (pubspec.flutterGen.assets.enabled) { for (final asset in pubspec.flutter.assets) { + final FlavoredAsset flavored; String assetInput; if (asset is YamlMap) { - assetInput = asset['path'] as String; + flavored = FlavoredAsset( + path: asset['path'], + flavors: + (asset['flavors'] as YamlList?)?.toSet().cast() ?? {}, + ); + assetInput = asset['path']; } else { - assetInput = asset as String; + flavored = FlavoredAsset(path: asset as String); + assetInput = asset; } if (assetInput.isEmpty) { continue; @@ -77,7 +85,7 @@ class FlutterGenBuilder extends Builder { assetInput += '*'; } await for (final assetId in buildStep.findAssets(Glob(assetInput))) { - assets.add(assetId.path); + assets.add(flavored.copyWith(path: assetId.path)); } } } @@ -107,16 +115,16 @@ class FlutterGenBuilder extends Builder { } class _FlutterGenBuilderState { - final Digest pubspecDigest; - final HashSet assets; - final HashMap colors; - - _FlutterGenBuilderState({ + const _FlutterGenBuilderState({ required this.pubspecDigest, required this.assets, required this.colors, }); + final Digest pubspecDigest; + final HashSet assets; + final HashMap colors; + bool shouldSkipGenerate(_FlutterGenBuilderState? previous) { if (previous == null) return false; return pubspecDigest == previous.pubspecDigest && From d712672c7600280faaded47eba016f1c4b424610 Mon Sep 17 00:00:00 2001 From: Alex Li Date: Tue, 18 Jun 2024 00:39:10 +0800 Subject: [PATCH 08/14] =?UTF-8?q?=F0=9F=92=A1=20Comment=20sort?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/test/assets_gen_test.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/core/test/assets_gen_test.dart b/packages/core/test/assets_gen_test.dart index 826ed271f..1391af13d 100644 --- a/packages/core/test/assets_gen_test.dart +++ b/packages/core/test/assets_gen_test.dart @@ -156,18 +156,18 @@ void main() { 'assets/français.jpg': 'franAis', // Dart Reserved Words + // allowed 'assets/async.png': 'async', // allowed 'assets/abstract.png': 'abstract', - // allowed + // must be suffixed (but can use Png) 'assets/await.png': 'awaitPng', // must be suffixed (but can use Png) 'assets/assert.png': 'assertPng', - // must be suffixed (but can use Png) - 'assets/await': 'await_', // must be suffixed - 'assets/assert': 'assert_', + 'assets/await': 'await_', // must be suffixed + 'assets/assert': 'assert_', // Asset with a number as the first character 'assets/7up.png': 'a7up', From 3bfb2733f569710ccb812ee922d7291ad1f49f17 Mon Sep 17 00:00:00 2001 From: Alex Li Date: Tue, 18 Jun 2024 07:23:00 +0800 Subject: [PATCH 09/14] =?UTF-8?q?=F0=9F=A7=AA=20Adds=20the=20flavored=20te?= =?UTF-8?q?st?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/test/assets_gen_test.dart | 8 + .../actual_data/assets_flavored.gen.dart | 367 ++++++++++++++++++ .../pubspec_assets_flavored.yaml | 28 ++ 3 files changed, 403 insertions(+) create mode 100644 packages/core/test_resources/actual_data/assets_flavored.gen.dart create mode 100644 packages/core/test_resources/pubspec_assets_flavored.yaml diff --git a/packages/core/test/assets_gen_test.dart b/packages/core/test/assets_gen_test.dart index 1391af13d..b5738f74a 100644 --- a/packages/core/test/assets_gen_test.dart +++ b/packages/core/test/assets_gen_test.dart @@ -127,6 +127,14 @@ void main() { await expectedAssetsGen(pubspec, generated, fact); }); + test('Assets with flavored assets', () async { + const pubspec = 'test_resources/pubspec_assets_flavored.yaml'; + const fact = 'test_resources/actual_data/assets_flavored.gen.dart'; + const generated = 'test_resources/lib/gen/assets_flavored.gen.dart'; + + await expectedAssetsGen(pubspec, generated, fact); + }); + test('Assets with terrible names (camelCase)', () async { // See [AssetTypeIterable.mapToUniqueAssetType] for the rules for picking // identifer names. diff --git a/packages/core/test_resources/actual_data/assets_flavored.gen.dart b/packages/core/test_resources/actual_data/assets_flavored.gen.dart new file mode 100644 index 000000000..d4f9c96ae --- /dev/null +++ b/packages/core/test_resources/actual_data/assets_flavored.gen.dart @@ -0,0 +1,367 @@ +/// GENERATED CODE - DO NOT MODIFY BY HAND +/// ***************************************************** +/// FlutterGen +/// ***************************************************** + +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: directives_ordering,unnecessary_import,implicit_dynamic_list_literal,deprecated_member_use + +import 'package:flutter/widgets.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:vector_graphics/vector_graphics.dart'; +import 'package:flare_flutter/flare_actor.dart'; +import 'package:flare_flutter/flare_controller.dart'; + +class $PicturesGen { + const $PicturesGen(); + + /// File path: pictures/chip5.jpg + AssetGenImage get chip5 => const AssetGenImage('pictures/chip5.jpg'); + + /// List of all assets + List get values => [chip5]; +} + +class $AssetsFlareGen { + const $AssetsFlareGen(); + + /// File path: assets/flare/Penguin.flr + FlareGenImage get penguin => const FlareGenImage('assets/flare/Penguin.flr'); + + /// List of all assets + List get values => [penguin]; +} + +class $AssetsImagesGen { + const $AssetsImagesGen(); + + /// File path: assets/images/chip1.jpg + AssetGenImage get chip1 => const AssetGenImage('assets/images/chip1.jpg'); + + /// File path: assets/images/chip2.jpg + AssetGenImage get chip2 => const AssetGenImage('assets/images/chip2.jpg'); + + /// Directory path: assets/images/chip3 + $AssetsImagesChip3Gen get chip3 => const $AssetsImagesChip3Gen(); + + /// Directory path: assets/images/chip4 + $AssetsImagesChip4Gen get chip4 => const $AssetsImagesChip4Gen(); + + /// Directory path: assets/images/icons + $AssetsImagesIconsGen get icons => const $AssetsImagesIconsGen(); + + /// File path: assets/images/logo.png + AssetGenImage get logo => const AssetGenImage('assets/images/logo.png'); + + /// File path: assets/images/profile.jpg + AssetGenImage get profileJpg => + const AssetGenImage('assets/images/profile.jpg'); + + /// File path: assets/images/profile.png + AssetGenImage get profilePng => + const AssetGenImage('assets/images/profile.png'); + + /// List of all assets + List get values => + [chip1, chip2, logo, profileJpg, profilePng]; +} + +class $AssetsJsonGen { + const $AssetsJsonGen(); + + /// File path: assets/json/list.json + String get list => 'assets/json/list.json'; + + /// File path: assets/json/map.json + String get map => 'assets/json/map.json'; + + /// List of all assets + List get values => [list, map]; +} + +class $AssetsMovieGen { + const $AssetsMovieGen(); + + /// File path: assets/movie/the_earth.mp4 + String get theEarth => 'assets/movie/the_earth.mp4'; + + /// List of all assets + List get values => [theEarth]; +} + +class $AssetsUnknownGen { + const $AssetsUnknownGen(); + + /// File path: assets/unknown/unknown_mime_type.bk + String get unknownMimeType => 'assets/unknown/unknown_mime_type.bk'; + + /// List of all assets + List get values => [unknownMimeType]; +} + +class $AssetsImagesChip3Gen { + const $AssetsImagesChip3Gen(); + + /// File path: assets/images/chip3/chip3.jpg + AssetGenImage get chip3 => + const AssetGenImage('assets/images/chip3/chip3.jpg'); + + /// List of all assets + List get values => [chip3]; +} + +class $AssetsImagesChip4Gen { + const $AssetsImagesChip4Gen(); + + /// File path: assets/images/chip4/chip4.jpg + AssetGenImage get chip4 => const AssetGenImage( + 'assets/images/chip4/chip4.jpg', + flavors: {'test'}, + ); + + /// List of all assets + List get values => [chip4]; +} + +class $AssetsImagesIconsGen { + const $AssetsImagesIconsGen(); + + /// File path: assets/images/icons/dart@test.svg + SvgGenImage get dartTest => + const SvgGenImage('assets/images/icons/dart@test.svg'); + + /// File path: assets/images/icons/fuchsia.svg + SvgGenImage get fuchsia => + const SvgGenImage('assets/images/icons/fuchsia.svg'); + + /// File path: assets/images/icons/kmm.svg + SvgGenImage get kmm => const SvgGenImage('assets/images/icons/kmm.svg'); + + /// File path: assets/images/icons/paint.svg + SvgGenImage get paint => const SvgGenImage('assets/images/icons/paint.svg'); + + /// List of all assets + List get values => [dartTest, fuchsia, kmm, paint]; +} + +class Assets { + Assets._(); + + static const String changelog = 'CHANGELOG.md'; + static const $AssetsFlareGen flare = $AssetsFlareGen(); + static const $AssetsImagesGen images = $AssetsImagesGen(); + static const $AssetsJsonGen json = $AssetsJsonGen(); + static const $AssetsMovieGen movie = $AssetsMovieGen(); + static const $AssetsUnknownGen unknown = $AssetsUnknownGen(); + static const $PicturesGen pictures = $PicturesGen(); + + /// List of all assets + static List get values => [changelog]; +} + +class AssetGenImage { + const AssetGenImage( + this._assetName, { + this.size, + this.flavors = const {}, + }); + + final String _assetName; + + final Size? size; + final Set flavors; + + Image image({ + Key? key, + AssetBundle? bundle, + ImageFrameBuilder? frameBuilder, + ImageErrorWidgetBuilder? errorBuilder, + String? semanticLabel, + bool excludeFromSemantics = false, + double? scale, + double? width, + double? height, + Color? color, + Animation? opacity, + BlendMode? colorBlendMode, + BoxFit? fit, + AlignmentGeometry alignment = Alignment.center, + ImageRepeat repeat = ImageRepeat.noRepeat, + Rect? centerSlice, + bool matchTextDirection = false, + bool gaplessPlayback = false, + bool isAntiAlias = false, + String? package, + FilterQuality filterQuality = FilterQuality.low, + int? cacheWidth, + int? cacheHeight, + }) { + return Image.asset( + _assetName, + key: key, + bundle: bundle, + frameBuilder: frameBuilder, + errorBuilder: errorBuilder, + semanticLabel: semanticLabel, + excludeFromSemantics: excludeFromSemantics, + scale: scale, + width: width, + height: height, + color: color, + opacity: opacity, + colorBlendMode: colorBlendMode, + fit: fit, + alignment: alignment, + repeat: repeat, + centerSlice: centerSlice, + matchTextDirection: matchTextDirection, + gaplessPlayback: gaplessPlayback, + isAntiAlias: isAntiAlias, + package: package, + filterQuality: filterQuality, + cacheWidth: cacheWidth, + cacheHeight: cacheHeight, + ); + } + + ImageProvider provider({ + AssetBundle? bundle, + String? package, + }) { + return AssetImage( + _assetName, + bundle: bundle, + package: package, + ); + } + + String get path => _assetName; + + String get keyName => _assetName; +} + +class SvgGenImage { + const SvgGenImage( + this._assetName, { + this.size, + this.flavors = const {}, + }) : _isVecFormat = false; + + const SvgGenImage.vec( + this._assetName, { + this.size, + this.flavors = const {}, + }) : _isVecFormat = true; + + final String _assetName; + final Size? size; + final Set flavors; + final bool _isVecFormat; + + SvgPicture svg({ + Key? key, + bool matchTextDirection = false, + AssetBundle? bundle, + String? package, + double? width, + double? height, + BoxFit fit = BoxFit.contain, + AlignmentGeometry alignment = Alignment.center, + bool allowDrawingOutsideViewBox = false, + WidgetBuilder? placeholderBuilder, + String? semanticsLabel, + bool excludeFromSemantics = false, + SvgTheme? theme, + ColorFilter? colorFilter, + Clip clipBehavior = Clip.hardEdge, + @deprecated Color? color, + @deprecated BlendMode colorBlendMode = BlendMode.srcIn, + @deprecated bool cacheColorFilter = false, + }) { + final BytesLoader loader; + if (_isVecFormat) { + loader = AssetBytesLoader( + _assetName, + assetBundle: bundle, + packageName: package, + ); + } else { + loader = SvgAssetLoader( + _assetName, + assetBundle: bundle, + packageName: package, + ); + } + return SvgPicture( + loader, + key: key, + matchTextDirection: matchTextDirection, + width: width, + height: height, + fit: fit, + alignment: alignment, + allowDrawingOutsideViewBox: allowDrawingOutsideViewBox, + placeholderBuilder: placeholderBuilder, + semanticsLabel: semanticsLabel, + excludeFromSemantics: excludeFromSemantics, + theme: theme, + colorFilter: colorFilter ?? + (color == null ? null : ColorFilter.mode(color, colorBlendMode)), + clipBehavior: clipBehavior, + cacheColorFilter: cacheColorFilter, + ); + } + + String get path => _assetName; + + String get keyName => _assetName; +} + +class FlareGenImage { + const FlareGenImage( + this._assetName, { + this.flavors = const {}, + }); + + final String _assetName; + final Set flavors; + + FlareActor flare({ + String? boundsNode, + String? animation, + BoxFit fit = BoxFit.contain, + Alignment alignment = Alignment.center, + bool isPaused = false, + bool snapToEnd = false, + FlareController? controller, + FlareCompletedCallback? callback, + Color? color, + bool shouldClip = true, + bool sizeFromArtboard = false, + String? artboard, + bool antialias = true, + }) { + return FlareActor( + _assetName, + boundsNode: boundsNode, + animation: animation, + fit: fit, + alignment: alignment, + isPaused: isPaused, + snapToEnd: snapToEnd, + controller: controller, + callback: callback, + color: color, + shouldClip: shouldClip, + sizeFromArtboard: sizeFromArtboard, + artboard: artboard, + antialias: antialias, + ); + } + + String get path => _assetName; + + String get keyName => _assetName; +} diff --git a/packages/core/test_resources/pubspec_assets_flavored.yaml b/packages/core/test_resources/pubspec_assets_flavored.yaml new file mode 100644 index 000000000..aa185e4a0 --- /dev/null +++ b/packages/core/test_resources/pubspec_assets_flavored.yaml @@ -0,0 +1,28 @@ +name: test + +flutter_gen: + output: lib/gen/ # Optional (default: lib/gen/) + line_length: 80 # Optional (default: 80) + + integrations: + flutter_svg: true + flare_flutter: true + +flutter: + assets: + - assets/images + - assets/images/chip3/chip3.jpg + - assets/images/chip3/chip3.jpg # duplicated + - assets/images/icons/fuchsia.svg + - assets/images/icons/kmm.svg + - assets/images/icons/paint.svg + - assets/images/icons/dart@test.svg + - assets/json/ + - pictures/chip5.jpg + - assets/flare/ + - assets/movie/ + - assets/unknown/unknown_mime_type.bk + - CHANGELOG.md + - path: assets/images/chip4/ + flavors: + - test From 74a3ab20a5ec7991558852a033a5c6c85a1781fa Mon Sep 17 00:00:00 2001 From: Alex Li Date: Tue, 18 Jun 2024 08:11:12 +0800 Subject: [PATCH 10/14] =?UTF-8?q?=E2=9C=85=20Improves=20the=20coverage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../test/assets_gen_integrations_test.dart | 61 +++++++++++++++++++ packages/core/test/config_test.dart | 30 ++++++++- 2 files changed, 90 insertions(+), 1 deletion(-) diff --git a/packages/core/test/assets_gen_integrations_test.dart b/packages/core/test/assets_gen_integrations_test.dart index f9637f141..66002d32b 100644 --- a/packages/core/test/assets_gen_integrations_test.dart +++ b/packages/core/test/assets_gen_integrations_test.dart @@ -1,5 +1,6 @@ @TestOn('vm') import 'package:flutter_gen_core/generators/integrations/flare_integration.dart'; +import 'package:flutter_gen_core/generators/integrations/integration.dart'; import 'package:flutter_gen_core/generators/integrations/lottie_integration.dart'; import 'package:flutter_gen_core/generators/integrations/rive_integration.dart'; import 'package:flutter_gen_core/generators/integrations/svg_integration.dart'; @@ -9,6 +10,27 @@ import 'package:test/test.dart'; import 'gen_test_helper.dart'; +class TestIntegration extends Integration { + TestIntegration() : super(''); + + @override + String get className => 'TestIntegration'; + + @override + String get classOutput => throw UnimplementedError(); + + @override + bool get isConstConstructor => true; + + @override + bool isSupport(AssetType asset) { + return true; + } + + @override + List get requiredImports => []; +} + void main() { group('Test Assets Integration generator', () { final resPath = p.absolute('test_resources'); @@ -21,6 +43,15 @@ void main() { await expectedAssetsGen(pubspec, generated, fact); }); + test('Integration.classInstantiate', () { + expect( + TestIntegration().classInstantiate( + AssetType(rootPath: resPath, path: 'assets/path', flavors: {'test'}), + ), + 'TestIntegration(\'assets/path\', flavors: {\'test\'},)', + ); + }); + test('Assets with Svg integrations on pubspec.yaml', () async { const pubspec = 'test_resources/pubspec_assets_svg_integrations.yaml'; const fact = @@ -42,6 +73,26 @@ void main() { ), 'SvgGenImage(\'assets/path\')', ); + expect( + integration.classInstantiate( + AssetType( + rootPath: resPath, + path: 'assets/path', + flavors: {'test'}, + ), + ), + 'SvgGenImage(\'assets/path\', flavors: {\'test\'},)', + ); + expect( + integration.classInstantiate( + AssetType( + rootPath: resPath, + path: 'assets/path/dog.vec', + flavors: {}, + ), + ), + 'SvgGenImage.vec(\'assets/path/dog.vec\')', + ); expect( integration.isSupport( AssetType( @@ -52,6 +103,16 @@ void main() { ), isTrue, ); + expect( + integration.isSupport( + AssetType( + rootPath: resPath, + path: 'assets/path/dog.vec', + flavors: {}, + ), + ), + isTrue, + ); expect( integration.isSupport( AssetType( diff --git a/packages/core/test/config_test.dart b/packages/core/test/config_test.dart index ab73b3a23..3fc759903 100644 --- a/packages/core/test/config_test.dart +++ b/packages/core/test/config_test.dart @@ -1 +1,29 @@ -void main() {} +import 'package:flutter_gen_core/settings/flavored_asset.dart'; +import 'package:test/test.dart'; + +void main() { + group(FlavoredAsset, () { + test('constructor', () { + expect( + FlavoredAsset(path: '').toString(), + 'FlavoredAsset(path: , flavors: {})', + ); + expect( + FlavoredAsset(path: 'assets/path'), + isA(), + ); + expect( + FlavoredAsset(path: 'assets/path', flavors: {}), + isA(), + ); + expect( + FlavoredAsset(path: 'assets/path', flavors: {'test'}), + isA(), + ); + expect( + FlavoredAsset(path: '1').copyWith(path: '2'), + predicate((e) => e.path == '2'), + ); + }); + }); +} From 847c5588efd441fa2419b5ccacf2be63b1942519 Mon Sep 17 00:00:00 2001 From: Alex Li Date: Tue, 18 Jun 2024 09:12:11 +0800 Subject: [PATCH 11/14] =?UTF-8?q?=F0=9F=8E=A8=20Split=20run=20and=20expect?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/test/gen_test_helper.dart | 116 ++++++++++++++++++------ 1 file changed, 88 insertions(+), 28 deletions(-) diff --git a/packages/core/test/gen_test_helper.dart b/packages/core/test/gen_test_helper.dart index e6c48d82b..6543fc595 100644 --- a/packages/core/test/gen_test_helper.dart +++ b/packages/core/test/gen_test_helper.dart @@ -12,22 +12,41 @@ import 'package:test/test.dart'; Future clearTestResults() async {} -/// Assets -Future expectedAssetsGen( - String pubspec, String generated, String fact) async { - await FlutterGenerator(File(pubspec), assetsName: p.basename(generated)) - .build(); +Future> runAssetsGen( + String pubspec, + String generated, + String fact, +) async { + await FlutterGenerator( + File(pubspec), + assetsName: p.basename(generated), + ).build(); final pubspecFile = File(pubspec); final config = loadPubspecConfig(pubspecFile); final formatter = DartFormatter( - pageWidth: config.pubspec.flutterGen.lineLength, lineEnding: '\n'); + pageWidth: config.pubspec.flutterGen.lineLength, + lineEnding: '\n', + ); final actual = generateAssets( - AssetsGenConfig.fromConfig(pubspecFile, config), formatter); - final expected = - formatter.format(File(fact).readAsStringSync().replaceAll('\r\n', '\n')); + AssetsGenConfig.fromConfig(pubspecFile, config), + formatter, + ); + final expected = formatter.format( + File(fact).readAsStringSync().replaceAll('\r\n', '\n'), + ); + return [actual, expected]; +} +/// Assets +Future expectedAssetsGen( + String pubspec, + String generated, + String fact, +) async { + final results = await runAssetsGen(pubspec, generated, fact); + final actual = results.first, expected = results.last; expect( File(generated).readAsStringSync(), isNotEmpty, @@ -35,22 +54,42 @@ Future expectedAssetsGen( expect(actual, expected); } -/// Colors -Future expectedColorsGen( - String pubspec, String generated, String fact) async { - await FlutterGenerator(File(pubspec), colorsName: p.basename(generated)) - .build(); +Future> runColorsGen( + String pubspec, + String generated, + String fact, +) async { + await FlutterGenerator( + File(pubspec), + colorsName: p.basename(generated), + ).build(); final pubspecFile = File(pubspec); final config = loadPubspecConfig(pubspecFile); final formatter = DartFormatter( - pageWidth: config.pubspec.flutterGen.lineLength, lineEnding: '\n'); + pageWidth: config.pubspec.flutterGen.lineLength, + lineEnding: '\n', + ); - final actual = - generateColors(pubspecFile, formatter, config.pubspec.flutterGen.colors); - final expected = - formatter.format(File(fact).readAsStringSync().replaceAll('\r\n', '\n')); + final actual = generateColors( + pubspecFile, + formatter, + config.pubspec.flutterGen.colors, + ); + final expected = formatter.format( + File(fact).readAsStringSync().replaceAll('\r\n', '\n'), + ); + return [actual, expected]; +} +/// Colors +Future expectedColorsGen( + String pubspec, + String generated, + String fact, +) async { + final results = await runColorsGen(pubspec, generated, fact); + final actual = results.first, expected = results.last; expect( File(generated).readAsStringSync(), isNotEmpty, @@ -58,22 +97,43 @@ Future expectedColorsGen( expect(actual, expected); } -/// Fonts -Future expectedFontsGen( - String pubspec, String generated, String fact) async { - await FlutterGenerator(File(pubspec), fontsName: p.basename(generated)) - .build(); +Future> runFontsGen( + String pubspec, + String generated, + String fact, +) async { + await FlutterGenerator( + File(pubspec), + fontsName: p.basename(generated), + ).build(); final pubspecFile = File(pubspec); final config = loadPubspecConfig(pubspecFile); final formatter = DartFormatter( - pageWidth: config.pubspec.flutterGen.lineLength, lineEnding: '\n'); + pageWidth: config.pubspec.flutterGen.lineLength, + lineEnding: '\n', + ); final actual = generateFonts( - formatter, config.pubspec.flutter.fonts, config.pubspec.flutterGen.fonts); - final expected = - formatter.format(File(fact).readAsStringSync().replaceAll('\r\n', '\n')); + formatter, + config.pubspec.flutter.fonts, + config.pubspec.flutterGen.fonts, + ); + final expected = formatter.format( + File(fact).readAsStringSync().replaceAll('\r\n', '\n'), + ); + + return [actual, expected]; +} +/// Fonts +Future expectedFontsGen( + String pubspec, + String generated, + String fact, +) async { + final results = await runFontsGen(pubspec, generated, fact); + final actual = results.first, expected = results.last; expect( File(generated).readAsStringSync(), isNotEmpty, From 777c224b189fd160a4a3915af6161ccbc1366aaf Mon Sep 17 00:00:00 2001 From: Alex Li Date: Tue, 18 Jun 2024 09:12:40 +0800 Subject: [PATCH 12/14] =?UTF-8?q?=E2=9C=85=20Add=20more=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/test/assets_gen_test.dart | 14 +++++++++ packages/core/test/config_test.dart | 7 +++++ ...bspec_assets_flavored_duplicate_entry.yaml | 31 +++++++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 packages/core/test_resources/pubspec_assets_flavored_duplicate_entry.yaml diff --git a/packages/core/test/assets_gen_test.dart b/packages/core/test/assets_gen_test.dart index b5738f74a..ec2d11f41 100644 --- a/packages/core/test/assets_gen_test.dart +++ b/packages/core/test/assets_gen_test.dart @@ -135,6 +135,20 @@ void main() { await expectedAssetsGen(pubspec, generated, fact); }); + test('Assets with duplicate flavoring entries', () async { + const pubspec = + 'test_resources/pubspec_assets_flavored_duplicate_entry.yaml'; + const fact = + 'test_resources/actual_data/assets_flavored_duplicate_entry.gen.dart'; + const generated = + 'test_resources/lib/gen/assets_flavored_duplicate_entry.gen.dart'; + + await expectLater( + () => runAssetsGen(pubspec, generated, fact), + throwsA(isA()), + ); + }); + test('Assets with terrible names (camelCase)', () async { // See [AssetTypeIterable.mapToUniqueAssetType] for the rules for picking // identifer names. diff --git a/packages/core/test/config_test.dart b/packages/core/test/config_test.dart index 3fc759903..53cc117d6 100644 --- a/packages/core/test/config_test.dart +++ b/packages/core/test/config_test.dart @@ -1,3 +1,4 @@ +import 'package:collection/collection.dart'; import 'package:flutter_gen_core/settings/flavored_asset.dart'; import 'package:test/test.dart'; @@ -24,6 +25,12 @@ void main() { FlavoredAsset(path: '1').copyWith(path: '2'), predicate((e) => e.path == '2'), ); + expect( + FlavoredAsset(path: '1').copyWith(flavors: {'test'}), + predicate( + (e) => SetEquality().equals(e.flavors, {'test'}), + ), + ); }); }); } diff --git a/packages/core/test_resources/pubspec_assets_flavored_duplicate_entry.yaml b/packages/core/test_resources/pubspec_assets_flavored_duplicate_entry.yaml new file mode 100644 index 000000000..53a4af6e9 --- /dev/null +++ b/packages/core/test_resources/pubspec_assets_flavored_duplicate_entry.yaml @@ -0,0 +1,31 @@ +name: test + +flutter_gen: + output: lib/gen/ # Optional (default: lib/gen/) + line_length: 80 # Optional (default: 80) + + integrations: + flutter_svg: true + flare_flutter: true + +flutter: + assets: + - assets/images + - assets/images/chip3/chip3.jpg + - assets/images/chip3/chip3.jpg # duplicated + - assets/images/icons/fuchsia.svg + - assets/images/icons/kmm.svg + - assets/images/icons/paint.svg + - assets/images/icons/dart@test.svg + - assets/json/ + - pictures/chip5.jpg + - assets/flare/ + - assets/movie/ + - assets/unknown/unknown_mime_type.bk + - CHANGELOG.md + - path: assets/images/chip4/ + flavors: + - test + - path: assets/images/chip4/ + flavors: + - another_test From b22d2362c8d126e08d1e6f3fe1715658f4990c05 Mon Sep 17 00:00:00 2001 From: Alex Li Date: Tue, 18 Jun 2024 09:28:11 +0800 Subject: [PATCH 13/14] =?UTF-8?q?=F0=9F=93=9D=20README?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index f051ef4a8..ab26d201d 100644 --- a/README.md +++ b/README.md @@ -167,6 +167,18 @@ flutter: These configurations will generate **`assets.gen.dart`** under the **`lib/gen/`** directory by default. +#### Flavored assets + +Flutter supports +[Conditionally bundling assets based on flavor](https://docs.flutter.dev/deployment/flavors#conditionally-bundling-assets-based-on-flavor). +Assets are only available with flavors if specified. +`flutter_gen` will generate the specified `flavors` for assets regardless the current flavor. +The `flavors` field accessible though `.flavors`, for example: + +```dart +print(MyAssets.images.chip4.flavors); // -> {'extern'} +``` + #### Excluding generating for assets You can specify `flutter_gen > assets > exclude` using `Glob` patterns to exclude particular assets. From c315e1962a6ea86aa22e15cbcc8c901bd2723e9b Mon Sep 17 00:00:00 2001 From: Alex Li Date: Sat, 22 Jun 2024 11:30:25 +0800 Subject: [PATCH 14/14] =?UTF-8?q?=F0=9F=93=A6=EF=B8=8F=20Update=20generate?= =?UTF-8?q?d=20files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/example/lib/gen/assets.gen.dart | 2 +- packages/core/test_resources/actual_data/assets.gen.dart | 2 +- .../test_resources/actual_data/assets_directory_path.gen.dart | 2 +- .../core/test_resources/actual_data/assets_flavored.gen.dart | 2 +- .../actual_data/assets_package_parameter.gen.dart | 2 +- .../test_resources/actual_data/assets_parse_metadata.gen.dart | 2 +- .../test_resources/actual_data/assets_svg_integrations.gen.dart | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/example/lib/gen/assets.gen.dart b/examples/example/lib/gen/assets.gen.dart index 8a740f6e8..ff963ec28 100644 --- a/examples/example/lib/gen/assets.gen.dart +++ b/examples/example/lib/gen/assets.gen.dart @@ -348,6 +348,7 @@ class SvgGenImage { _assetName, assetBundle: bundle, packageName: package, + theme: theme, ); } return SvgPicture( @@ -362,7 +363,6 @@ class SvgGenImage { placeholderBuilder: placeholderBuilder, semanticsLabel: semanticsLabel, excludeFromSemantics: excludeFromSemantics, - theme: theme, colorFilter: colorFilter ?? (color == null ? null : ColorFilter.mode(color, colorBlendMode)), clipBehavior: clipBehavior, diff --git a/packages/core/test_resources/actual_data/assets.gen.dart b/packages/core/test_resources/actual_data/assets.gen.dart index d543ae110..acf5974b7 100644 --- a/packages/core/test_resources/actual_data/assets.gen.dart +++ b/packages/core/test_resources/actual_data/assets.gen.dart @@ -290,6 +290,7 @@ class SvgGenImage { _assetName, assetBundle: bundle, packageName: package, + theme: theme, ); } return SvgPicture( @@ -304,7 +305,6 @@ class SvgGenImage { placeholderBuilder: placeholderBuilder, semanticsLabel: semanticsLabel, excludeFromSemantics: excludeFromSemantics, - theme: theme, colorFilter: colorFilter ?? (color == null ? null : ColorFilter.mode(color, colorBlendMode)), clipBehavior: clipBehavior, diff --git a/packages/core/test_resources/actual_data/assets_directory_path.gen.dart b/packages/core/test_resources/actual_data/assets_directory_path.gen.dart index a68bf81fb..e4025aad4 100644 --- a/packages/core/test_resources/actual_data/assets_directory_path.gen.dart +++ b/packages/core/test_resources/actual_data/assets_directory_path.gen.dart @@ -208,6 +208,7 @@ class SvgGenImage { _assetName, assetBundle: bundle, packageName: package, + theme: theme, ); } return SvgPicture( @@ -222,7 +223,6 @@ class SvgGenImage { placeholderBuilder: placeholderBuilder, semanticsLabel: semanticsLabel, excludeFromSemantics: excludeFromSemantics, - theme: theme, colorFilter: colorFilter ?? (color == null ? null : ColorFilter.mode(color, colorBlendMode)), clipBehavior: clipBehavior, diff --git a/packages/core/test_resources/actual_data/assets_flavored.gen.dart b/packages/core/test_resources/actual_data/assets_flavored.gen.dart index d4f9c96ae..987e64ade 100644 --- a/packages/core/test_resources/actual_data/assets_flavored.gen.dart +++ b/packages/core/test_resources/actual_data/assets_flavored.gen.dart @@ -292,6 +292,7 @@ class SvgGenImage { _assetName, assetBundle: bundle, packageName: package, + theme: theme, ); } return SvgPicture( @@ -306,7 +307,6 @@ class SvgGenImage { placeholderBuilder: placeholderBuilder, semanticsLabel: semanticsLabel, excludeFromSemantics: excludeFromSemantics, - theme: theme, colorFilter: colorFilter ?? (color == null ? null : ColorFilter.mode(color, colorBlendMode)), clipBehavior: clipBehavior, diff --git a/packages/core/test_resources/actual_data/assets_package_parameter.gen.dart b/packages/core/test_resources/actual_data/assets_package_parameter.gen.dart index 04cdf5f70..21f1b1a9b 100644 --- a/packages/core/test_resources/actual_data/assets_package_parameter.gen.dart +++ b/packages/core/test_resources/actual_data/assets_package_parameter.gen.dart @@ -206,6 +206,7 @@ class SvgGenImage { _assetName, assetBundle: bundle, packageName: package, + theme: theme, ); } return SvgPicture( @@ -220,7 +221,6 @@ class SvgGenImage { placeholderBuilder: placeholderBuilder, semanticsLabel: semanticsLabel, excludeFromSemantics: excludeFromSemantics, - theme: theme, colorFilter: colorFilter ?? (color == null ? null : ColorFilter.mode(color, colorBlendMode)), clipBehavior: clipBehavior, diff --git a/packages/core/test_resources/actual_data/assets_parse_metadata.gen.dart b/packages/core/test_resources/actual_data/assets_parse_metadata.gen.dart index 36b275c7c..ef4968182 100644 --- a/packages/core/test_resources/actual_data/assets_parse_metadata.gen.dart +++ b/packages/core/test_resources/actual_data/assets_parse_metadata.gen.dart @@ -299,6 +299,7 @@ class SvgGenImage { _assetName, assetBundle: bundle, packageName: package, + theme: theme, ); } return SvgPicture( @@ -313,7 +314,6 @@ class SvgGenImage { placeholderBuilder: placeholderBuilder, semanticsLabel: semanticsLabel, excludeFromSemantics: excludeFromSemantics, - theme: theme, colorFilter: colorFilter ?? (color == null ? null : ColorFilter.mode(color, colorBlendMode)), clipBehavior: clipBehavior, diff --git a/packages/core/test_resources/actual_data/assets_svg_integrations.gen.dart b/packages/core/test_resources/actual_data/assets_svg_integrations.gen.dart index 88ddd5b1e..8eedabddb 100644 --- a/packages/core/test_resources/actual_data/assets_svg_integrations.gen.dart +++ b/packages/core/test_resources/actual_data/assets_svg_integrations.gen.dart @@ -90,6 +90,7 @@ class SvgGenImage { _assetName, assetBundle: bundle, packageName: package, + theme: theme, ); } return SvgPicture( @@ -104,7 +105,6 @@ class SvgGenImage { placeholderBuilder: placeholderBuilder, semanticsLabel: semanticsLabel, excludeFromSemantics: excludeFromSemantics, - theme: theme, colorFilter: colorFilter ?? (color == null ? null : ColorFilter.mode(color, colorBlendMode)), clipBehavior: clipBehavior,