diff --git a/README.md b/README.md index 5c3e01d7..7a63385e 100644 --- a/README.md +++ b/README.md @@ -204,7 +204,10 @@ flutter: - assets/images/ - assets/images/chip3/chip.jpg - assets/images/chip4/chip.jpg - - assets/images/icons/paint.svg + - path: assets/images/icons/paint.svg + - path: assets/images/icons/transformed.svg + transformers: + - package: vector_graphics_compiler - assets/images/icons/dart@test.svg - assets/json/fruits.json - assets/flare/Penguin.flr @@ -380,7 +383,7 @@ flutter_gen: image: false ``` -If you are using SVG images with [flutter_svg](https://pub.dev/packages/flutter_svg) you can use the integration feature. +If you are using SVG images with [flutter_svg](https://pub.dev/packages/flutter_svg) you can use the integration feature. This feature also supports using `vector_graphics_compiler` transformer and the produced code will use the `AssetBytesLoader` for such transformed assets. ```yaml # pubspec.yaml @@ -391,6 +394,9 @@ flutter_gen: flutter: assets: - assets/images/icons/paint.svg + - path: assets/images/icons/transformed.svg + transformers: + - package: vector_graphics_compiler ``` ```dart diff --git a/packages/core/lib/generators/assets_generator.dart b/packages/core/lib/generators/assets_generator.dart index 3b0a3222..32b077d8 100644 --- a/packages/core/lib/generators/assets_generator.dart +++ b/packages/core/lib/generators/assets_generator.dart @@ -176,24 +176,33 @@ List _getAssetRelativePathList( ) { // Normalize. final normalizedAssets = {...assets.whereType()}; - final normalizingMap = >{}; - // Resolve flavored assets. + final normalizingMap = + flavors, Set transformers})>{}; + // Resolve flavored or transformed assets. for (final map in assets.whereType()) { final path = (map['path'] as String).trim(); final flavors = (map['flavors'] as YamlList?)?.toSet().cast() ?? {}; + final transformers = (map['transformers'] as YamlList?) + ?.map(((t) => (t as YamlMap)['package'] as String)) + .toSet() ?? + {}; 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.', + 'but they specify different lists of flavors or transformers.', ); } - normalizingMap[path] = flavors; + normalizingMap[path] = (flavors: flavors, transformers: transformers); } for (final entry in normalizingMap.entries) { normalizedAssets.add( - YamlMap.wrap({'path': entry.key, 'flavors': entry.value}), + YamlMap.wrap({ + 'path': entry.key, + 'flavors': entry.value.flavors, + 'transformers': entry.value.transformers, + }), ); } @@ -201,7 +210,11 @@ List _getAssetRelativePathList( for (final asset in normalizedAssets) { final FlavoredAsset tempAsset; if (asset is YamlMap) { - tempAsset = FlavoredAsset(path: asset['path'], flavors: asset['flavors']); + tempAsset = FlavoredAsset( + path: asset['path'], + flavors: asset['flavors'], + transformers: asset['transformers'], + ); } else { tempAsset = FlavoredAsset(path: (asset as String).trim()); } @@ -238,14 +251,24 @@ AssetType _constructAssetTree( ) { // Relative path is the key final assetTypeMap = { - '.': AssetType(rootPath: rootPath, path: '.', flavors: {}), + '.': AssetType( + rootPath: rootPath, + path: '.', + flavors: {}, + transformers: {}, + ), }; for (final asset in assetRelativePathList) { String path = asset.path; while (path != '.') { assetTypeMap.putIfAbsent( path, - () => AssetType(rootPath: rootPath, path: path, flavors: asset.flavors), + () => AssetType( + rootPath: rootPath, + path: path, + flavors: asset.flavors, + transformers: asset.transformers, + ), ); path = dirname(path); } @@ -462,6 +485,7 @@ Future _flatStyleDefinition( rootPath: config.rootPath, path: assetPath.path, flavors: assetPath.flavors, + transformers: assetPath.transformers, ), ) .mapToUniqueAssetType(style) diff --git a/packages/core/lib/generators/integrations/svg_integration.dart b/packages/core/lib/generators/integrations/svg_integration.dart index 568a48fd..778fec23 100644 --- a/packages/core/lib/generators/integrations/svg_integration.dart +++ b/packages/core/lib/generators/integrations/svg_integration.dart @@ -103,12 +103,15 @@ ${isPackage ? "\n static const String package = '$packageName';" : ''} @override String get className => 'SvgGenImage'; + static const vectorCompileTransformer = 'vector_graphics_compiler'; + @override String classInstantiate(AssetType asset) { // Query extra information about the SVG. final info = parseMetadata ? _getMetadata(asset) : null; final buffer = StringBuffer(className); - if (asset.extension == '.vec') { + if (asset.extension == '.vec' || + asset.transformers.contains(vectorCompileTransformer)) { buffer.write('.vec'); } buffer.write('('); diff --git a/packages/core/lib/settings/asset_type.dart b/packages/core/lib/settings/asset_type.dart index 872c96ba..8b2a666b 100644 --- a/packages/core/lib/settings/asset_type.dart +++ b/packages/core/lib/settings/asset_type.dart @@ -10,11 +10,13 @@ class AssetType { required this.rootPath, required this.path, required this.flavors, + required this.transformers, }); final String rootPath; final String path; final Set flavors; + final Set transformers; final List _children = List.empty(growable: true); late final children = _children.sortedBy((e) => e.path); @@ -55,7 +57,8 @@ class AssetType { String toString() => 'AssetType(' 'rootPath: $rootPath, ' 'path: $path, ' - 'flavors: $flavors' + 'flavors: $flavors, ' + 'transformers: $transformers' ')'; } @@ -74,6 +77,7 @@ class UniqueAssetType extends AssetType { rootPath: assetType.rootPath, path: assetType.path, flavors: assetType.flavors, + transformers: assetType.transformers, ); /// Convert the asset name to a correctly styled name, e.g camelCase or @@ -113,7 +117,9 @@ class UniqueAssetType extends AssetType { 'path: $path, ' 'style: $style, ' 'needExtension: $needExtension, ' - 'suffix: $suffix}'; + 'suffix: $suffix, ' + 'flavors: $flavors, ' + 'transformers: $transformers}'; } } diff --git a/packages/core/lib/settings/flavored_asset.dart b/packages/core/lib/settings/flavored_asset.dart index 66e24aa0..c08905c7 100644 --- a/packages/core/lib/settings/flavored_asset.dart +++ b/packages/core/lib/settings/flavored_asset.dart @@ -2,18 +2,26 @@ class FlavoredAsset { const FlavoredAsset({ required this.path, this.flavors = const {}, + this.transformers = const {}, }); final String path; final Set flavors; + final Set transformers; - FlavoredAsset copyWith({String? path, Set? flavors}) { + FlavoredAsset copyWith({ + String? path, + Set? flavors, + Set? transformers, + }) { return FlavoredAsset( path: path ?? this.path, flavors: flavors ?? this.flavors, + transformers: transformers ?? this.transformers, ); } @override - String toString() => 'FlavoredAsset(path: $path, flavors: $flavors)'; + String toString() => + 'FlavoredAsset(path: $path, flavors: $flavors, transformers: $transformers)'; } diff --git a/packages/core/test/assets_gen_integrations_test.dart b/packages/core/test/assets_gen_integrations_test.dart index a09d08f2..95957bf0 100644 --- a/packages/core/test/assets_gen_integrations_test.dart +++ b/packages/core/test/assets_gen_integrations_test.dart @@ -45,7 +45,12 @@ void main() { test('Integration.classInstantiate', () { expect( TestIntegration().classInstantiate( - AssetType(rootPath: resPath, path: 'assets/path', flavors: {'test'}), + AssetType( + rootPath: resPath, + path: 'assets/path', + flavors: {'test'}, + transformers: {}, + ), ), 'TestIntegration(\'assets/path\', flavors: {\'test\'},)', ); @@ -63,6 +68,7 @@ void main() { rootPath: resPath, path: 'assets/path', flavors: {}, + transformers: {}, ), ), 'SvgGenImage(\'assets/path\')', @@ -73,26 +79,62 @@ void main() { rootPath: resPath, path: 'assets/path', flavors: {'test'}, + transformers: {}, ), ), 'SvgGenImage(\'assets/path\', flavors: {\'test\'},)', ); + expect( + integration.classInstantiate( + AssetType( + rootPath: resPath, + path: 'assets/path/dog.svg', + flavors: {}, + transformers: {}, + ), + ), + 'SvgGenImage(\'assets/path/dog.svg\')', + ); expect( integration.classInstantiate( AssetType( rootPath: resPath, path: 'assets/path/dog.vec', flavors: {}, + transformers: {}, ), ), 'SvgGenImage.vec(\'assets/path/dog.vec\')', ); + expect( + integration.classInstantiate( + AssetType( + rootPath: resPath, + path: 'assets/path/dog.svg', + flavors: {}, + transformers: {'test'}, + ), + ), + 'SvgGenImage(\'assets/path/dog.svg\')', + ); + expect( + integration.classInstantiate( + AssetType( + rootPath: resPath, + path: 'assets/path/dog.svg', + flavors: {}, + transformers: {'vector_graphics_compiler'}, + ), + ), + 'SvgGenImage.vec(\'assets/path/dog.svg\')', + ); expect( integration.isSupport( AssetType( rootPath: resPath, path: 'assets/path/dog.svg', flavors: {}, + transformers: {}, ), ), isTrue, @@ -103,6 +145,18 @@ void main() { rootPath: resPath, path: 'assets/path/dog.vec', flavors: {}, + transformers: {}, + ), + ), + isTrue, + ); + expect( + integration.isSupport( + AssetType( + rootPath: resPath, + path: 'assets/path/dog.svg', + flavors: {}, + transformers: {'test'}, ), ), isTrue, @@ -113,6 +167,7 @@ void main() { rootPath: resPath, path: 'assets/path/dog.png', flavors: {}, + transformers: {}, ), ), isFalse, @@ -147,6 +202,7 @@ void main() { rootPath: resPath, path: 'assets/path', flavors: {}, + transformers: {}, ), ), 'RiveGenImage(\'assets/path\')', @@ -157,6 +213,7 @@ void main() { rootPath: resPath, path: 'assets/path/dog.riv', flavors: {}, + transformers: {}, ), ), isTrue, @@ -167,6 +224,7 @@ void main() { rootPath: resPath, path: 'assets/path/dog.json', flavors: {}, + transformers: {}, ), ), isFalse, @@ -194,6 +252,7 @@ void main() { rootPath: resPath, path: 'assets/lottie', flavors: {}, + transformers: {}, ), ), 'LottieGenImage(\'assets/lottie\')', @@ -204,6 +263,7 @@ void main() { rootPath: resPath, path: 'assets/lottie/hamburger_arrow.json', flavors: {}, + transformers: {}, ), ), isTrue, @@ -214,6 +274,7 @@ void main() { rootPath: resPath, path: 'assets/lottie/hamburger_arrow_without_version.json', flavors: {}, + transformers: {}, ), ), isFalse, diff --git a/packages/core/test/assets_gen_test.dart b/packages/core/test/assets_gen_test.dart index c15df926..a0120477 100644 --- a/packages/core/test/assets_gen_test.dart +++ b/packages/core/test/assets_gen_test.dart @@ -167,7 +167,14 @@ void main() { final List assets = tests.keys .sorted() - .map((e) => AssetType(rootPath: '', path: e, flavors: {})) + .map( + (e) => AssetType( + rootPath: '', + path: e, + flavors: {}, + transformers: {}, + ), + ) .toList(); final got = assets.mapToUniqueAssetType(camelCase); diff --git a/packages/core/test/settings_test.dart b/packages/core/test/settings_test.dart index 6a419132..b1baeb1a 100644 --- a/packages/core/test/settings_test.dart +++ b/packages/core/test/settings_test.dart @@ -11,6 +11,7 @@ void main() { rootPath: 'root', path: 'assets/single.jpg', flavors: {'flavor'}, + transformers: {'transformer'}, ); expect(assetType, isA()); expect(assetType.name, 'assets/single'); @@ -23,9 +24,16 @@ void main() { (e) => const SetEquality().equals(e.flavors, {'flavor'}), ), ); + expect( + assetType, + predicate( + (e) => const SetEquality().equals(e.transformers, {'transformer'}), + ), + ); expect( assetType.toString(), - 'AssetType(rootPath: root, path: assets/single.jpg, flavors: {flavor})', + 'AssetType(rootPath: root, path: assets/single.jpg, ' + 'flavors: {flavor}, transformers: {transformer})', ); }); }); @@ -34,7 +42,7 @@ void main() { test('constructor', () { expect( const FlavoredAsset(path: '').toString(), - 'FlavoredAsset(path: , flavors: {})', + 'FlavoredAsset(path: , flavors: {}, transformers: {})', ); expect( const FlavoredAsset(path: 'assets/path'), @@ -48,6 +56,10 @@ void main() { const FlavoredAsset(path: 'assets/path', flavors: {'test'}), isA(), ); + expect( + const FlavoredAsset(path: 'assets/path', transformers: {'test'}), + isA(), + ); expect( const FlavoredAsset(path: '1').copyWith(path: '2'), predicate((e) => e.path == '2'), @@ -58,6 +70,12 @@ void main() { (e) => const SetEquality().equals(e.flavors, {'test'}), ), ); + expect( + const FlavoredAsset(path: '1').copyWith(transformers: {'test'}), + predicate( + (e) => const SetEquality().equals(e.transformers, {'test'}), + ), + ); }); }); diff --git a/packages/core/test_resources/actual_data/assets_assets_svg_integrations.gen.dart b/packages/core/test_resources/actual_data/assets_assets_svg_integrations.gen.dart index 6457b702..7f69e593 100644 --- a/packages/core/test_resources/actual_data/assets_assets_svg_integrations.gen.dart +++ b/packages/core/test_resources/actual_data/assets_assets_svg_integrations.gen.dart @@ -30,8 +30,11 @@ class $AssetsImagesIconsGen { SvgGenImage get fuchsia => const SvgGenImage('assets/images/icons/fuchsia.svg'); + /// File path: assets/images/icons/kmm.svg + SvgGenImage get kmm => const SvgGenImage.vec('assets/images/icons/kmm.svg'); + /// List of all assets - List get values => [dartTest, fuchsia]; + List get values => [dartTest, fuchsia, kmm]; } class Assets { diff --git a/packages/core/test_resources/actual_data/build_assets_build_assets.gen.dart b/packages/core/test_resources/actual_data/build_assets_build_assets.gen.dart index 76b5439a..ef265e5f 100644 --- a/packages/core/test_resources/actual_data/build_assets_build_assets.gen.dart +++ b/packages/core/test_resources/actual_data/build_assets_build_assets.gen.dart @@ -54,13 +54,16 @@ class $AssetsImagesGen { AssetGenImage get logo => const AssetGenImage('assets/images/logo.png'); /// File path: assets/images/profile.jpg - AssetGenImage get profileJpg => const AssetGenImage('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'); + AssetGenImage get profilePng => + const AssetGenImage('assets/images/profile.png'); /// List of all assets - List get values => [chip1, chip2, logo, profileJpg, profilePng]; + List get values => + [chip1, chip2, logo, profileJpg, profilePng]; } class $AssetsJsonGen { @@ -100,7 +103,8 @@ class $AssetsImagesChip3Gen { const $AssetsImagesChip3Gen(); /// File path: assets/images/chip3/chip3.jpg - AssetGenImage get chip3 => const AssetGenImage('assets/images/chip3/chip3.jpg'); + AssetGenImage get chip3 => + const AssetGenImage('assets/images/chip3/chip3.jpg'); /// List of all assets List get values => [chip3]; @@ -110,7 +114,8 @@ 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'); /// List of all assets List get values => [chip4]; @@ -120,10 +125,12 @@ class $AssetsImagesIconsGen { const $AssetsImagesIconsGen(); /// File path: assets/images/icons/dart@test.svg - SvgGenImage get dartTest => const SvgGenImage('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'); + 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'); @@ -298,7 +305,8 @@ class SvgGenImage { placeholderBuilder: placeholderBuilder, semanticsLabel: semanticsLabel, excludeFromSemantics: excludeFromSemantics, - colorFilter: colorFilter ?? (color == null ? null : ColorFilter.mode(color, colorBlendMode)), + colorFilter: colorFilter ?? + (color == null ? null : ColorFilter.mode(color, colorBlendMode)), clipBehavior: clipBehavior, cacheColorFilter: cacheColorFilter, ); diff --git a/packages/core/test_resources/actual_data/build_assets_build_runner_assets.gen.dart b/packages/core/test_resources/actual_data/build_assets_build_runner_assets.gen.dart index 19ecaaf9..44a4288a 100644 --- a/packages/core/test_resources/actual_data/build_assets_build_runner_assets.gen.dart +++ b/packages/core/test_resources/actual_data/build_assets_build_runner_assets.gen.dart @@ -54,13 +54,16 @@ class $AssetsImagesGen { AssetGenImage get logo => const AssetGenImage('assets/images/logo.png'); /// File path: assets/images/profile.jpg - AssetGenImage get profileJpg => const AssetGenImage('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'); + AssetGenImage get profilePng => + const AssetGenImage('assets/images/profile.png'); /// List of all assets - List get values => [chip1, chip2, logo, profileJpg, profilePng]; + List get values => + [chip1, chip2, logo, profileJpg, profilePng]; } class $AssetsJsonGen { @@ -100,7 +103,8 @@ class $AssetsImagesChip3Gen { const $AssetsImagesChip3Gen(); /// File path: assets/images/chip3/chip3.jpg - AssetGenImage get chip3 => const AssetGenImage('assets/images/chip3/chip3.jpg'); + AssetGenImage get chip3 => + const AssetGenImage('assets/images/chip3/chip3.jpg'); /// List of all assets List get values => [chip3]; @@ -110,7 +114,8 @@ 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'); /// List of all assets List get values => [chip4]; @@ -120,10 +125,12 @@ class $AssetsImagesIconsGen { const $AssetsImagesIconsGen(); /// File path: assets/images/icons/dart@test.svg - SvgGenImage get dartTest => const SvgGenImage('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'); + 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'); @@ -298,7 +305,8 @@ class SvgGenImage { placeholderBuilder: placeholderBuilder, semanticsLabel: semanticsLabel, excludeFromSemantics: excludeFromSemantics, - colorFilter: colorFilter ?? (color == null ? null : ColorFilter.mode(color, colorBlendMode)), + colorFilter: colorFilter ?? + (color == null ? null : ColorFilter.mode(color, colorBlendMode)), clipBehavior: clipBehavior, cacheColorFilter: cacheColorFilter, ); diff --git a/packages/core/test_resources/pubspec_assets_svg_integrations.yaml b/packages/core/test_resources/pubspec_assets_svg_integrations.yaml index b43861e9..3ab9ea3e 100644 --- a/packages/core/test_resources/pubspec_assets_svg_integrations.yaml +++ b/packages/core/test_resources/pubspec_assets_svg_integrations.yaml @@ -11,3 +11,6 @@ flutter: assets: - assets/images/icons/dart@test.svg - assets/images/icons/fuchsia.svg + - path: assets/images/icons/kmm.svg + transformers: + - package: vector_graphics_compiler