buildPainterClass function Null safety

String buildPainterClass(
  1. String iconName,
  2. XmlDocument xmlDocument,
  3. int width,
  4. int height
)

Implementation

String buildPainterClass(String iconName, XmlDocument xmlDocument, int width, int height) {

  final XmlElement svgElement =  xmlDocument.findElements('svg').first;

  final painterClass = Class((classBuilder) {
    classBuilder.name = '_${iconName}Painter';
    classBuilder.extend = refer('CustomPainter', 'package:flutter/material.dart');

    classBuilder.constructors.add(Constructor((constructorBuilder) {
      constructorBuilder.optionalParameters.add(
        Parameter((parameterBuilder) {
          parameterBuilder.type = refer('Color', 'package:flutter/material.dart');
          parameterBuilder.name = 'color';
          parameterBuilder.named = true;
          parameterBuilder.required = true;
        })
      );
      constructorBuilder.initializers.add(
          const Code('_paint = Paint()')
      );
      constructorBuilder.body = const Code('''
        _paint.color = color;
        _paint.style = PaintingStyle.fill;
      ''');
    }));

    classBuilder.fields.add(Field((fieldBuilder) {
      fieldBuilder.name = 'width';
      fieldBuilder.type = refer('double');
      fieldBuilder.modifier = FieldModifier.final$;
      fieldBuilder.assignment = Code('${width}');
    }));

    classBuilder.fields.add(Field((fieldBuilder) {
      fieldBuilder.name = 'height';
      fieldBuilder.type = refer('double');
      fieldBuilder.modifier = FieldModifier.final$;
      fieldBuilder.assignment = Code('${height}');
    }));

    classBuilder.fields.add(Field((fieldBuilder) {
      fieldBuilder.name = '_paint';
      fieldBuilder.modifier = FieldModifier.final$;
      fieldBuilder.type = refer('Paint', 'package:flutter/material.dart');
    }));

    classBuilder.methods.add(Method.returnsVoid((methodBuilder) {
      methodBuilder.name = 'setColor';
      methodBuilder.requiredParameters.addAll([
        Parameter((parameterBuilder) {
          parameterBuilder.name = 'color';
          parameterBuilder.type = refer('Color', 'package:flutter/material.dart');
        }),
      ]);
      methodBuilder.body = const Code(
        '_paint.color = color;'
      );
    }));

    classBuilder.methods.add(Method.returnsVoid((methodBuilder) {
      methodBuilder.name = 'paint';
      methodBuilder.requiredParameters.addAll([
        Parameter((parameterBuilder) {
          parameterBuilder.name = 'canvas';
          parameterBuilder.type = refer('Canvas', 'package:flutter/material.dart');
        }),
        Parameter((parameterBuilder) {
          parameterBuilder.name = 'size';
          parameterBuilder.type = refer('Size', 'package:flutter/material.dart');
        }),
      ]);
      methodBuilder.annotations.add(refer('override'));


      final List<Code> codeList = <Code>[];
      _traverseSvgXmlTree(codeList, element: svgElement);

      methodBuilder.body = Block.of([
        const Code('''
          final Matrix4 matrix4 = Matrix4.identity();
          matrix4.scale(size.width / width, size.height / height);
        '''),
        ...codeList
      ]);
    }));

    classBuilder.methods.add(Method((methodBuilder) {
      methodBuilder.name = 'shouldRepaint';
      methodBuilder.annotations.add(refer('override'));
      methodBuilder.requiredParameters.add(Parameter((parameterBuilder) {
        parameterBuilder.type = refer(classBuilder.name!);
        parameterBuilder.name = 'oldDelegate';
      }));
      methodBuilder.body = const Code('return oldDelegate._paint != _paint;');
      methodBuilder.returns = refer('bool');
    }));

  });


  final iconClass = Class((classBuilder) {
    classBuilder.name = '${iconName}Icon';
    classBuilder.extend = refer('StatelessWidget', 'package:flutter/material.dart');
    classBuilder.implements.add(
      refer('PaintedIcon', 'package:figma_icon_builder/painted_icon.dart'),
    );
    classBuilder.constructors.add(Constructor((constructorBuilder) {
      final Parameter keyParam = Parameter((parameterBuilder) {
        parameterBuilder.type = refer('Key?', 'package:flutter/material.dart');
        parameterBuilder.name = 'key';
        parameterBuilder.named = true;
      });

      final Parameter foregroundColorParam = Parameter((parameterBuilder) {
        parameterBuilder.name = 'foregroundColor';
        parameterBuilder.named = true;
        parameterBuilder.toThis = true;
      });

      final sizeParam = Parameter((parameterBuilder) {
        parameterBuilder.name = 'size';
        parameterBuilder.defaultTo = Code('const Size(${width}, ${height})');
        parameterBuilder.named = true;
        parameterBuilder.toThis = true;
      });

      constructorBuilder.optionalParameters.addAll([
        keyParam,
        foregroundColorParam,
        sizeParam
      ]);
      constructorBuilder.constant = true;
      constructorBuilder.initializers.add(
          Code('super(key: ${keyParam.name})')
      );

    }));

    classBuilder.fields.add(Field((fieldBuilder) {
      fieldBuilder.type = refer('Color?', 'package:flutter/material.dart');
      fieldBuilder.name = 'foregroundColor';
      fieldBuilder.modifier = FieldModifier.final$;
    }));

    classBuilder.fields.add(Field((fieldBuilder) {
      fieldBuilder.type = refer('Size', 'package:flutter/material.dart');
      fieldBuilder.name = 'size';
      fieldBuilder.modifier = FieldModifier.final$;
    }));

    classBuilder.methods.add(Method((methodBuilder) {
      methodBuilder.name = 'build';
      methodBuilder.annotations.add(refer('override'));
      methodBuilder.returns = refer('Widget', 'package:flutter/material.dart');
      methodBuilder.requiredParameters.addAll([
        Parameter((parameterBuilder) {
          parameterBuilder.name = 'context';
          parameterBuilder.type = refer('BuildContext');
        }),
      ]);
      methodBuilder.body = Block.of([
        Code('''
          final IconThemeData iconThemeData = IconTheme.of(context);
          return ConstrainedBox(
            constraints: BoxConstraints.tight(size),
            child: CustomPaint(
              key: key,
              painter: ${painterClass.name}(
                color: foregroundColor ?? iconThemeData.color ?? Colors.black,
              ),
              size: size,
            ),
          );
        '''),
      ]);

    }));

    classBuilder.methods.add(Method((methodBuilder) {
      methodBuilder.name = 'withColor';
      methodBuilder.annotations.add(refer('override'));
      methodBuilder.returns = refer('PaintedIcon');
      methodBuilder.requiredParameters.addAll([
        Parameter((parameterBuilder) {
          parameterBuilder.name = 'foregroundColor';
          parameterBuilder.type = refer('Color', 'package:flutter/material.dart');
        }),
      ]);

      methodBuilder.body = Block.of([
        Code('''
          return ${classBuilder.name}(
            key: key,
            foregroundColor: foregroundColor,
            size: size,
          );
        '''),
      ]);
    }));

    classBuilder.methods.add(Method((methodBuilder) {
      methodBuilder.name = 'withSize';
      methodBuilder.annotations.add(refer('override'));
      methodBuilder.returns = refer('PaintedIcon');
      methodBuilder.requiredParameters.addAll([
        Parameter((parameterBuilder) {
          parameterBuilder.name = 'size';
          parameterBuilder.type = refer('Size', 'package:flutter/material.dart');
        }),
      ]);

      methodBuilder.body = Block.of([
        Code('''
          return ${classBuilder.name}(
            key: key,
            foregroundColor: foregroundColor,
            size: size,
          );
        '''),
      ]);
    }));


  });

  final library = Library((libraryBuilder) {
    libraryBuilder.directives.addAll([
      Directive.import('package:flutter/material.dart'),
      Directive.import('package:path_drawing/path_drawing.dart'),
      Directive.import('package:figma_icon/figma_icon.dart'),
      Directive.import('package:flutter/rendering.dart'),
    ]);
    libraryBuilder.body.addAll([
      painterClass,
      iconClass
    ]);
  });


  final emitter = DartEmitter(
    allocator: Allocator.none,
    orderDirectives: false,
    useNullSafetySyntax: true
  );
  return DartFormatter().format('${library.accept(emitter)}');
}