diff --git a/.vscode/settings.json b/.vscode/settings.json index ecd7b661..3256b03e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,4 @@ { - "dart.flutterSdkPath": "~/.asdf/installs/flutter/3.0.1-stable", - "dart.sdkPath": "~/.asdf/installs/dart/2.17.1/dart-sdk" + "dart.flutterSdkPath": "~/.asdf/installs/flutter/3.0.5-stable", + "dart.sdkPath": "~/.asdf/installs/dart/2.17.6/dart-sdk" } diff --git a/README.md b/README.md index d720352b..04fc392f 100644 --- a/README.md +++ b/README.md @@ -739,16 +739,28 @@ flutter_gen: # - snake-case # - dot-delimiter style: dot-delimiter + # Optional + outputs: + # Default is Assets + class_name: MyAssets fonts: # Optional enabled: true + # Optional + outputs: + # Default is FontFamily + class_name: MyFontFamily colors: # Optional enabled: true # Optional inputs: [] + # Optional + outputs: + # Default is ColorName + class_name: MyColorName flutter: # See: https://flutter.dev/docs/development/ui/assets-and-images#specifying-assets diff --git a/example/lib/gen/assets.gen.dart b/example/lib/gen/assets.gen.dart index 91d9dbdc..2cacdc5c 100644 --- a/example/lib/gen/assets.gen.dart +++ b/example/lib/gen/assets.gen.dart @@ -14,13 +14,6 @@ import 'package:flare_flutter/flare_actor.dart'; import 'package:flare_flutter/flare_controller.dart'; import 'package:rive/rive.dart'; -class $PicturesGen { - const $PicturesGen(); - - /// File path: pictures/chip5.jpg - AssetGenImage get chip5 => const AssetGenImage('pictures/chip5.jpg'); -} - class $AssetsFlareGen { const $AssetsFlareGen(); @@ -37,7 +30,6 @@ class $AssetsImagesGen { /// File path: assets/images/chip2.jpg AssetGenImage get chip2 => const AssetGenImage('assets/images/chip2.jpg'); - $AssetsImagesChip3Gen get chip3 => const $AssetsImagesChip3Gen(); $AssetsImagesChip4Gen get chip4 => const $AssetsImagesChip4Gen(); $AssetsImagesIconsGen get icons => const $AssetsImagesIconsGen(); @@ -87,14 +79,6 @@ class $AssetsUnknownGen { String get unknownMimeType => 'assets/unknown/unknown_mime_type.bk'; } -class $AssetsImagesChip3Gen { - const $AssetsImagesChip3Gen(); - - /// File path: assets/images/chip3/chip3.jpg - AssetGenImage get chip3 => - const AssetGenImage('assets/images/chip3/chip3.jpg'); -} - class $AssetsImagesChip4Gen { const $AssetsImagesChip4Gen(); @@ -130,7 +114,6 @@ class Assets { static const $AssetsMovieGen movie = $AssetsMovieGen(); static const $AssetsRiveGen rive = $AssetsRiveGen(); static const $AssetsUnknownGen unknown = $AssetsUnknownGen(); - static const $PicturesGen pictures = $PicturesGen(); } class AssetGenImage { diff --git a/example/lib/main.dart b/example/lib/main.dart index 2948e452..327cf4c7 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -55,12 +55,12 @@ void main() async { width: 120, height: 120, ), - Assets.pictures.chip5.image( - key: const Key("chip5"), - width: 120, - height: 120, - fit: BoxFit.scaleDown, - ), + // Assets.pictures.chip5.image( + // key: const Key("chip5"), + // width: 120, + // height: 120, + // fit: BoxFit.scaleDown, + // ), const Text( 'Hi there, I\'m FlutterGen', style: TextStyle( diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 4b02a1c5..95dfce1d 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -7,7 +7,7 @@ version: 1.0.0+2 environment: sdk: ">=2.16.0 <3.0.0" - flutter: ">=2.10.4" + flutter: ">=3.0.0" dependencies: flutter: @@ -131,6 +131,10 @@ flutter_gen: # Assets.images.chip (default style) # style: dot-delimiter + exclude: + - assets/images/chip3/chip3.jpg + - pictures/chip5.jpg + - assets/flare/ fonts: enabled: true diff --git a/example_resources/pubspec.yaml b/example_resources/pubspec.yaml index 3bdd4bd6..677ae04f 100644 --- a/example_resources/pubspec.yaml +++ b/example_resources/pubspec.yaml @@ -7,7 +7,7 @@ version: 1.0.0+2 environment: sdk: ">=2.16.0 <3.0.0" - flutter: ">=2.10.4" + flutter: ">=3.0.0" dependencies: flutter: diff --git a/packages/core/lib/flutter_generator.dart b/packages/core/lib/flutter_generator.dart index 8ff32d5f..067b97ce 100644 --- a/packages/core/lib/flutter_generator.dart +++ b/packages/core/lib/flutter_generator.dart @@ -76,7 +76,11 @@ class FlutterGenerator { } if (flutterGen.fonts.enabled && flutter.fonts.isNotEmpty) { - final generated = generateFonts(formatter, flutter.fonts); + final generated = generateFonts( + formatter, + flutter.fonts, + genFonts: flutterGen.fonts, + ); final fonts = File(normalize(join(pubspecFile.parent.path, output, fontsName))); writeAsString(generated, file: fonts); diff --git a/packages/core/lib/generators/assets_generator.dart b/packages/core/lib/generators/assets_generator.dart index 8f9dd355..accf25d1 100644 --- a/packages/core/lib/generators/assets_generator.dart +++ b/packages/core/lib/generators/assets_generator.dart @@ -4,6 +4,7 @@ import 'dart:io'; import 'package:collection/collection.dart'; import 'package:dart_style/dart_style.dart'; import 'package:dartx/dartx.dart'; +import 'package:glob/glob.dart'; import 'package:path/path.dart'; import '../settings/asset_type.dart'; @@ -23,6 +24,7 @@ class AssetsGenConfig { this._packageName, this.flutterGen, this.assets, + this.exclude, ); factory AssetsGenConfig.fromConfig(File pubspecFile, Config config) { @@ -31,6 +33,9 @@ class AssetsGenConfig { config.pubspec.packageName, config.pubspec.flutterGen, config.pubspec.flutter.assets, + config.pubspec.flutterGen.assets.exclude + .map((pattern) => Glob(pattern)) + .toList(), ); } @@ -38,6 +43,7 @@ class AssetsGenConfig { final String _packageName; final FlutterGen flutterGen; final List assets; + final List exclude; String get packageParameterLiteral => flutterGen.assets.packageParameterEnabled ? _packageName : ''; @@ -99,6 +105,7 @@ String generateAssets( List _getAssetRelativePathList( String rootPath, List assets, + List excludes, ) { final assetRelativePathList = []; for (final assetName in assets) { @@ -113,7 +120,14 @@ List _getAssetRelativePathList( assetRelativePathList.add(relative(assetAbsolutePath, from: rootPath)); } } - return assetRelativePathList; + + if (excludes.isEmpty) { + return assetRelativePathList; + } + + return assetRelativePathList + .where((file) => !excludes.any((exclude) => exclude.matches(file))) + .toList(); } AssetType _constructAssetTree(List assetRelativePathList) { @@ -199,8 +213,12 @@ String _dotDelimiterStyleDefinition( List integrations, ) { final buffer = StringBuffer(); - final assetRelativePathList = - _getAssetRelativePathList(config.rootPath, config.assets); + final className = config.flutterGen.assets.outputs?.className; + final assetRelativePathList = _getAssetRelativePathList( + config.rootPath, + config.assets, + config.exclude, + ); final assetsStaticStatements = <_Statement>[]; final assetTypeQueue = ListQueue.from( @@ -249,8 +267,8 @@ String _dotDelimiterStyleDefinition( assetTypeQueue.addAll(assetType.children); } } - buffer - .writeln(_dotDelimiterStyleAssetsClassDefinition(assetsStaticStatements)); + buffer.writeln(_dotDelimiterStyleAssetsClassDefinition( + className, assetsStaticStatements)); return buffer.toString(); } @@ -291,7 +309,11 @@ String _flatStyleDefinition( List integrations, String Function(AssetTypeIsUniqueWithoutExtension) createName, ) { - final statements = _getAssetRelativePathList(config.rootPath, config.assets) + final statements = _getAssetRelativePathList( + config.rootPath, + config.assets, + config.exclude, + ) .distinct() .sorted() .map((relativePath) => AssetType(relativePath)) @@ -306,27 +328,34 @@ String _flatStyleDefinition( ) .whereType<_Statement>() .toList(); - return _flatStyleAssetsClassDefinition(statements); + final className = config.flutterGen.assets.outputs?.className; + return _flatStyleAssetsClassDefinition(className, statements); } -String _flatStyleAssetsClassDefinition(List<_Statement> statements) { +String _flatStyleAssetsClassDefinition( + String? className, + List<_Statement> statements, +) { final statementsBlock = statements.map((statement) => '''${statement.toDartDocString()} ${statement.toStaticFieldString()} ''').join('\n'); - return _assetsClassDefinition(statementsBlock); + return _assetsClassDefinition(className, statementsBlock); } -String _dotDelimiterStyleAssetsClassDefinition(List<_Statement> statements) { +String _dotDelimiterStyleAssetsClassDefinition( + String? className, + List<_Statement> statements, +) { final statementsBlock = statements.map((statement) => statement.toStaticFieldString()).join('\n'); - return _assetsClassDefinition(statementsBlock); + return _assetsClassDefinition(className, statementsBlock); } -String _assetsClassDefinition(String statementsBlock) { +String _assetsClassDefinition(String? className, String statementsBlock) { return ''' -class Assets { - Assets._(); +class ${className ?? 'Assets'} { + ${className ?? 'Assets'}._(); $statementsBlock } diff --git a/packages/core/lib/generators/colors_generator.dart b/packages/core/lib/generators/colors_generator.dart index 37ae1dd5..e421637f 100644 --- a/packages/core/lib/generators/colors_generator.dart +++ b/packages/core/lib/generators/colors_generator.dart @@ -15,25 +15,26 @@ import 'generator_helper.dart'; String generateColors( File pubspecFile, DartFormatter formatter, - FlutterGenColors colors, + FlutterGenColors genColors, ) { - if (colors.inputs.isEmpty) { + if (genColors.inputs.isEmpty) { throw const InvalidSettingsException( 'The value of "flutter_gen/colors:" is incorrect.'); } final buffer = StringBuffer(); + final className = genColors.outputs?.className ?? 'ColorName'; buffer.writeln(header); buffer.writeln(ignore); buffer.writeln("import 'package:flutter/painting.dart';"); buffer.writeln("import 'package:flutter/material.dart';"); buffer.writeln(); - buffer.writeln('class ColorName {'); - buffer.writeln('ColorName._();'); + buffer.writeln('class $className {'); + buffer.writeln('$className._();'); buffer.writeln(); final colorList = <_Color>[]; - colors.inputs + genColors.inputs .map((file) => ColorPath(join(pubspecFile.parent.path, file))) .forEach((colorFile) { final data = colorFile.file.readAsStringSync(); diff --git a/packages/core/lib/generators/fonts_generator.dart b/packages/core/lib/generators/fonts_generator.dart index f96e597a..a67ccdd1 100644 --- a/packages/core/lib/generators/fonts_generator.dart +++ b/packages/core/lib/generators/fonts_generator.dart @@ -10,18 +10,20 @@ import 'generator_helper.dart'; String generateFonts( DartFormatter formatter, - List fonts, -) { + List fonts, { + FlutterGenFonts? genFonts, +}) { if (fonts.isEmpty) { throw InvalidSettingsException( 'The value of "flutter/fonts:" is incorrect.'); } final buffer = StringBuffer(); + final className = genFonts?.outputs?.className ?? 'FontFamily'; buffer.writeln(header); buffer.writeln(ignore); - buffer.writeln('class FontFamily {'); - buffer.writeln('FontFamily._();'); + buffer.writeln('class $className {'); + buffer.writeln('$className._();'); buffer.writeln(); fonts.map((element) => element.family).distinct().sorted().forEach((family) { diff --git a/packages/core/lib/settings/config.dart b/packages/core/lib/settings/config.dart index 1b5cb9cf..aa962085 100644 --- a/packages/core/lib/settings/config.dart +++ b/packages/core/lib/settings/config.dart @@ -47,13 +47,20 @@ flutter_gen: enabled: true package_parameter_enabled: false style: dot-delimiter + outputs: + class_name: Assets + exclude: [] fonts: enabled: true + outputs: + class_name: FontFamily colors: enabled: true inputs: [] + outputs: + class_name: ColorName flutter: assets: [] diff --git a/packages/core/lib/settings/pubspec.dart b/packages/core/lib/settings/pubspec.dart index 76f388d7..5cb38a41 100644 --- a/packages/core/lib/settings/pubspec.dart +++ b/packages/core/lib/settings/pubspec.dart @@ -83,7 +83,11 @@ class FlutterGen { @JsonSerializable() class FlutterGenColors { - FlutterGenColors({required this.enabled, required this.inputs}); + FlutterGenColors({ + required this.enabled, + required this.inputs, + this.outputs, + }); @JsonKey(name: 'enabled', required: true) final bool enabled; @@ -91,6 +95,9 @@ class FlutterGenColors { @JsonKey(name: 'inputs', required: true) final List inputs; + @JsonKey(name: 'outputs', required: false) + final FlutterGenElementOutputs? outputs; + factory FlutterGenColors.fromJson(Map json) => _$FlutterGenColorsFromJson(json); } @@ -105,6 +112,8 @@ class FlutterGenAssets { required this.enabled, required this.packageParameterEnabled, required this.style, + this.outputs, + required this.exclude, }) { if (style != dotDelimiterStyle && style != snakeCaseStyle && @@ -122,6 +131,12 @@ class FlutterGenAssets { @JsonKey(name: 'style', required: true) final String style; + @JsonKey(name: 'outputs', required: false) + final FlutterGenElementOutputs? outputs; + + @JsonKey(name: 'exclude', required: true) + final List exclude; + bool get isDotDelimiterStyle => style == dotDelimiterStyle; bool get isSnakeCaseStyle => style == snakeCaseStyle; @@ -134,11 +149,14 @@ class FlutterGenAssets { @JsonSerializable() class FlutterGenFonts { - FlutterGenFonts({required this.enabled}); + FlutterGenFonts({required this.enabled, this.outputs}); @JsonKey(name: 'enabled', required: true) final bool enabled; + @JsonKey(name: 'outputs', required: false) + final FlutterGenElementOutputs? outputs; + factory FlutterGenFonts.fromJson(Map json) => _$FlutterGenFontsFromJson(json); } @@ -162,3 +180,14 @@ class FlutterGenIntegrations { factory FlutterGenIntegrations.fromJson(Map json) => _$FlutterGenIntegrationsFromJson(json); } + +@JsonSerializable() +class FlutterGenElementOutputs { + FlutterGenElementOutputs({this.className}); + + @JsonKey(name: 'class_name', required: false) + final String? className; + + factory FlutterGenElementOutputs.fromJson(Map json) => + _$FlutterGenElementOutputsFromJson(json); +} diff --git a/packages/core/lib/settings/pubspec.g.dart b/packages/core/lib/settings/pubspec.g.dart index ea42e5f8..15d7b4a6 100644 --- a/packages/core/lib/settings/pubspec.g.dart +++ b/packages/core/lib/settings/pubspec.g.dart @@ -106,6 +106,11 @@ FlutterGenColors _$FlutterGenColorsFromJson(Map json) => $checkedCreate( enabled: $checkedConvert('enabled', (v) => v as bool), inputs: $checkedConvert('inputs', (v) => (v as List).map((e) => e as String).toList()), + outputs: $checkedConvert( + 'outputs', + (v) => v == null + ? null + : FlutterGenElementOutputs.fromJson(v as Map)), ); return val; }, @@ -117,13 +122,25 @@ FlutterGenAssets _$FlutterGenAssetsFromJson(Map json) => $checkedCreate( ($checkedConvert) { $checkKeys( json, - requiredKeys: const ['enabled', 'package_parameter_enabled', 'style'], + requiredKeys: const [ + 'enabled', + 'package_parameter_enabled', + 'style', + 'exclude' + ], ); final val = FlutterGenAssets( enabled: $checkedConvert('enabled', (v) => v as bool), packageParameterEnabled: $checkedConvert('package_parameter_enabled', (v) => v as bool), style: $checkedConvert('style', (v) => v as String), + outputs: $checkedConvert( + 'outputs', + (v) => v == null + ? null + : FlutterGenElementOutputs.fromJson(v as Map)), + exclude: $checkedConvert('exclude', + (v) => (v as List).map((e) => e as String).toList()), ); return val; }, @@ -142,6 +159,11 @@ FlutterGenFonts _$FlutterGenFontsFromJson(Map json) => $checkedCreate( ); final val = FlutterGenFonts( enabled: $checkedConvert('enabled', (v) => v as bool), + outputs: $checkedConvert( + 'outputs', + (v) => v == null + ? null + : FlutterGenElementOutputs.fromJson(v as Map)), ); return val; }, @@ -168,3 +190,16 @@ FlutterGenIntegrations _$FlutterGenIntegrationsFromJson(Map json) => 'flareFlutter': 'flare_flutter' }, ); + +FlutterGenElementOutputs _$FlutterGenElementOutputsFromJson(Map json) => + $checkedCreate( + 'FlutterGenElementOutputs', + json, + ($checkedConvert) { + final val = FlutterGenElementOutputs( + className: $checkedConvert('class_name', (v) => v as String?), + ); + return val; + }, + fieldKeyMap: const {'className': 'class_name'}, + ); diff --git a/packages/core/pubspec.yaml b/packages/core/pubspec.yaml index bff99a5c..ea760dd7 100644 --- a/packages/core/pubspec.yaml +++ b/packages/core/pubspec.yaml @@ -22,6 +22,7 @@ dependencies: color: '>=3.0.0 <4.0.0' collection: '>=1.15.0 <2.0.0' json_annotation: '>=4.4.0 <5.0.0' + glob: '>=2.0.0 <3.0.0' dart_style: '>=2.0.0 <3.0.0' analyzer: '>=2.0.0 <5.0.0' diff --git a/packages/core/test/assets_gen_test.dart b/packages/core/test/assets_gen_test.dart index 40b2e034..f1a5055f 100644 --- a/packages/core/test/assets_gen_test.dart +++ b/packages/core/test/assets_gen_test.dart @@ -74,5 +74,15 @@ void main() { await expectedAssetsGen(pubspec, generated, fact); }); + + test('Assets with excluded files and directories', () async { + const pubspec = 'test_resources/pubspec_assets_exclude_files.yaml'; + const fact = + 'test_resources/actual_data/assets_package_exclude_files.gen.dart'; + const generated = + 'test_resources/lib/gen/assets_package_exclude_files.gen.dart'; + + await expectedAssetsGen(pubspec, generated, fact); + }); }); } 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 62f19c95..ba0ababb 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 @@ -119,6 +119,6 @@ class AssetGenImage { } String get path => _assetName; - + String get keyName => _assetName; } 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 new file mode 100644 index 00000000..ae41764c --- /dev/null +++ b/packages/core/test_resources/actual_data/assets_package_exclude_files.gen.dart @@ -0,0 +1,118 @@ +/// GENERATED CODE - DO NOT MODIFY BY HAND +/// ***************************************************** +/// FlutterGen +/// ***************************************************** + +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: directives_ordering,unnecessary_import + +import 'package:flutter/widgets.dart'; + +class $PicturesGen { + const $PicturesGen(); + + /// File path: pictures/chip5.jpg + AssetGenImage get chip5 => const AssetGenImage('pictures/chip5.jpg'); +} + +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'); + + $AssetsImagesChip4Gen get chip4 => const $AssetsImagesChip4Gen(); + + /// File path: assets/images/profile.jpg + AssetGenImage get profile => const AssetGenImage('assets/images/profile.jpg'); +} + +class $AssetsJsonGen { + const $AssetsJsonGen(); + + /// File path: assets/json/fruits.json + String get fruits => 'assets/json/fruits.json'; +} + +class $AssetsImagesChip4Gen { + const $AssetsImagesChip4Gen(); + + /// File path: assets/images/chip4/chip4.jpg + AssetGenImage get chip4 => + const AssetGenImage('assets/images/chip4/chip4.jpg'); +} + +class Assets { + Assets._(); + + static const $AssetsImagesGen images = $AssetsImagesGen(); + static const $AssetsJsonGen json = $AssetsJsonGen(); + static const $PicturesGen pictures = $PicturesGen(); +} + +class AssetGenImage { + const AssetGenImage(this._assetName); + + final String _assetName; + + 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, + ); + } + + String get path => _assetName; + + String get keyName => _assetName; +} diff --git a/packages/core/test_resources/pubspec_assets_exclude_files.yaml b/packages/core/test_resources/pubspec_assets_exclude_files.yaml new file mode 100644 index 00000000..55b77ddd --- /dev/null +++ b/packages/core/test_resources/pubspec_assets_exclude_files.yaml @@ -0,0 +1,28 @@ +name: test + +flutter_gen: + output: lib/gen/ + line_length: 80 + + integrations: + flutter_svg: true + + assets: + exclude: + - assets/images/chip3/*.jpg + - assets/images/*.png + - assets/**/icons/* + +flutter: + uses-material-design: true + assets: + - 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 + - assets/images/icons/dart@test.svg + - assets/json/fruits.json + - pictures/chip5.jpg \ No newline at end of file