diff --git a/analysis_options.yaml b/analysis_options.yaml index cded5ce5d..d2ca5de1c 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -6,6 +6,9 @@ analyzer: implicit-casts: false implicit-dynamic: false + plugins: + - dart_code_metrics + linter: rules: - always_declare_return_types @@ -72,3 +75,12 @@ linter: - use_rethrow_when_possible - unnecessary_new +dart_code_metrics: + rules: + - prefer-trailing-comma + metrics: + number-of-arguments: 8 + number-of-methods: 28 + lines-of-executable-code: 200 + cyclomatic-complexity: 36 + diff --git a/doc/examples/gestures/lib/main_overlapping_tapables.dart b/doc/examples/gestures/lib/main_overlapping_tapables.dart index 3593925ee..9cb217698 100644 --- a/doc/examples/gestures/lib/main_overlapping_tapables.dart +++ b/doc/examples/gestures/lib/main_overlapping_tapables.dart @@ -23,7 +23,11 @@ class TapableSquare extends PositionComponent with Tapable { Paint _randomPaint() { final rng = math.Random(); final color = Color.fromRGBO( - rng.nextInt(256), rng.nextInt(256), rng.nextInt(256), 0.9); + rng.nextInt(256), + rng.nextInt(256), + rng.nextInt(256), + 0.9, + ); return PaletteEntry(color).paint; } diff --git a/doc/examples/particles/lib/main.dart b/doc/examples/particles/lib/main.dart index 92bedd509..a7fed7553 100644 --- a/doc/examples/particles/lib/main.dart +++ b/doc/examples/particles/lib/main.dart @@ -304,11 +304,12 @@ class MyGame extends BaseGame { return Particle.generate( count: count, generator: (i) => TranslatedParticle( - offset: Offset( - (i % perLine) * colWidth - halfCellSize.x + imageSize, - (i ~/ perLine) * rowHeight - halfCellSize.y + imageSize, - ), - child: reusableImageParticle), + offset: Offset( + (i % perLine) * colWidth - halfCellSize.x + imageSize, + (i ~/ perLine) * rowHeight - halfCellSize.y + imageSize, + ), + child: reusableImageParticle, + ), ); } @@ -475,7 +476,7 @@ class MyGame extends BaseGame { .moving(to: cellSizeOffset.scale(1, -1)) .scaled(2) .translated(halfCellSizeOffset.scale(-1, 1)) - .accelerated(acceleration: halfCellSizeOffset.scale(-5, 5)) + .accelerated(acceleration: halfCellSizeOffset.scale(-5, 5)), ]); } @@ -488,7 +489,10 @@ class MyGame extends BaseGame { if (debugMode) { fpsTextConfig.render( - canvas, '${fps(120).toStringAsFixed(2)}fps', Vector2(0, size.y - 24)); + canvas, + '${fps(120).toStringAsFixed(2)}fps', + Vector2(0, size.y - 24), + ); } } diff --git a/doc/examples/spritesheet/lib/main.dart b/doc/examples/spritesheet/lib/main.dart index ff0ee3017..9ee9ee011 100644 --- a/doc/examples/spritesheet/lib/main.dart +++ b/doc/examples/spritesheet/lib/main.dart @@ -28,7 +28,9 @@ class MyGame extends BaseGame { final spriteSize = Vector2(80.0, 90.0); final vampireComponent = SpriteAnimationComponent.fromSpriteAnimation( - spriteSize, vampireAnimation) + spriteSize, + vampireAnimation, + ) ..x = 150 ..y = 100; diff --git a/doc/examples/text/lib/main.dart b/doc/examples/text/lib/main.dart index 33f8d3678..e5d0b85b7 100644 --- a/doc/examples/text/lib/main.dart +++ b/doc/examples/text/lib/main.dart @@ -40,10 +40,11 @@ class MyTextBox extends TextBoxComponent { height - margin.vertical, ); c.drawRect( - innerRect, - Paint() - ..color = BasicPalette.white.color - ..style = PaintingStyle.stroke); + innerRect, + Paint() + ..color = BasicPalette.white.color + ..style = PaintingStyle.stroke, + ); } } diff --git a/doc/examples/timer/lib/main.dart b/doc/examples/timer/lib/main.dart index 489c14898..e71d99970 100644 --- a/doc/examples/timer/lib/main.dart +++ b/doc/examples/timer/lib/main.dart @@ -13,18 +13,20 @@ class MyGameApp extends StatelessWidget { return MaterialApp(routes: { '/': (BuildContext context) => Column(children: [ ElevatedButton( - child: const Text('Game'), - onPressed: () { - Navigator.of(context).pushNamed('/game'); - }), + child: const Text('Game'), + onPressed: () { + Navigator.of(context).pushNamed('/game'); + }, + ), ElevatedButton( - child: const Text('BaseGame'), - onPressed: () { - Navigator.of(context).pushNamed('/base_game'); - }) + child: const Text('BaseGame'), + onPressed: () { + Navigator.of(context).pushNamed('/base_game'); + }, + ), ]), '/game': (BuildContext context) => GameWidget(game: MyGame()), - '/base_game': (BuildContext context) => GameWidget(game: MyBaseGame()) + '/base_game': (BuildContext context) => GameWidget(game: MyBaseGame()), }); } } diff --git a/doc/examples/widgets/lib/main.dart b/doc/examples/widgets/lib/main.dart index 99cdde28f..ecaa425cf 100644 --- a/doc/examples/widgets/lib/main.dart +++ b/doc/examples/widgets/lib/main.dart @@ -37,24 +37,25 @@ void main() async { final nineTileBoxImage = await Flame.images.load('nine_tile_box.png'); dashbook.storiesOf('NineTileBox').decorator(CenterDecorator()).add( - 'default', - (ctx) => Container( - width: ctx.numberProperty('width', 200), - height: ctx.numberProperty('height', 200), - child: NineTileBox( - image: nineTileBoxImage, - tileSize: 16, - destTileSize: 50, - child: const Center( - child: const Text( - 'Cool label', - style: const TextStyle( - color: const Color(0xFFFFFFFF), - ), + 'default', + (ctx) => Container( + width: ctx.numberProperty('width', 200), + height: ctx.numberProperty('height', 200), + child: NineTileBox( + image: nineTileBoxImage, + tileSize: 16, + destTileSize: 50, + child: const Center( + child: const Text( + 'Cool label', + style: const TextStyle( + color: const Color(0xFFFFFFFF), ), ), ), - )); + ), + ), + ); final buttonsImage = await Flame.images.load('buttons.png'); final _buttons = SpriteSheet( diff --git a/lib/image_composition.dart b/lib/image_composition.dart index 989583278..ec5abf756 100644 --- a/lib/image_composition.dart +++ b/lib/image_composition.dart @@ -101,7 +101,14 @@ class ImageComposition { ); _composes.add(_Composed( - image, position, source, angle, anchor, isAntiAlias, blendMode)); + image, + position, + source, + angle, + anchor, + isAntiAlias, + blendMode, + )); } void clear() => _composes.clear(); diff --git a/lib/src/components/joystick/joystick_events.dart b/lib/src/components/joystick/joystick_events.dart index ccbcfd66f..01dd9f41c 100644 --- a/lib/src/components/joystick/joystick_events.dart +++ b/lib/src/components/joystick/joystick_events.dart @@ -7,7 +7,7 @@ enum JoystickMoveDirectional { MOVE_DOWN_RIGHT, MOVE_DOWN_LEFT, MOVE_LEFT, - IDLE + IDLE, } enum ActionEvent { DOWN, UP, MOVE, CANCEL } diff --git a/lib/src/components/position_component.dart b/lib/src/components/position_component.dart index 63ac4846e..46dc12efa 100644 --- a/lib/src/components/position_component.dart +++ b/lib/src/components/position_component.dart @@ -113,7 +113,8 @@ abstract class PositionComponent extends BaseComponent { final corners = [ rotatePoint(absoluteTopLeftPosition), // Top-left rotatePoint( - absoluteTopLeftPosition + Vector2(0.0, size.y)), // Bottom-left + absoluteTopLeftPosition + Vector2(0.0, size.y), + ), // Bottom-left rotatePoint(absoluteTopLeftPosition + size), // Bottom-right rotatePoint(absoluteTopLeftPosition + Vector2(size.x, 0.0)), // Top-right ]; diff --git a/lib/src/particles/particle.dart b/lib/src/particles/particle.dart index 90ce52a50..08943488f 100644 --- a/lib/src/particles/particle.dart +++ b/lib/src/particles/particle.dart @@ -148,7 +148,11 @@ abstract class Particle { /// in radians with [RotatingParticle] Particle rotated([double angle = 0]) { return RotatingParticle( - child: this, lifespan: _lifespan, from: angle, to: angle); + child: this, + lifespan: _lifespan, + from: angle, + to: angle, + ); } /// Rotates this particle from given angle diff --git a/pubspec.yaml b/pubspec.yaml index 1d5e110f4..668a63b23 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,6 +14,7 @@ dev_dependencies: flutter_test: sdk: flutter test: ^1.9.4 + dart_code_metrics: ^2.4.0 environment: sdk: ">=2.7.0 <3.0.0" diff --git a/scripts/lint.sh b/scripts/lint.sh index 6f6b21020..045d7634d 100755 --- a/scripts/lint.sh +++ b/scripts/lint.sh @@ -18,6 +18,12 @@ done cd . flutter pub get +result=$(flutter pub run dart_code_metrics:metrics .) +if [ "$result" != "" ]; then + echo "flutter dart code metrics issues: $1" + echo "$result" + exit 1 +fi result=$(flutter analyze .) if ! echo "$result" | grep -q "No issues found!"; then echo "$result" diff --git a/test/base_game_test.dart b/test/base_game_test.dart index 5675ba839..9ce5bb998 100644 --- a/test/base_game_test.dart +++ b/test/base_game_test.dart @@ -75,21 +75,23 @@ void main() { expect(true, game.components.contains(component)); }); - test('when the component has onLoad function, adds after load completion', - () async { - final MyGame game = MyGame(); - final MyAsyncComponent component = MyAsyncComponent(); + test( + 'when the component has onLoad function, adds after load completion', + () async { + final MyGame game = MyGame(); + final MyAsyncComponent component = MyAsyncComponent(); - game.onResize(size); - await game.add(component); - // runs a cycle to add the component - game.update(0.1); + game.onResize(size); + await game.add(component); + // runs a cycle to add the component + game.update(0.1); - expect(true, game.components.contains(component)); + expect(true, game.components.contains(component)); - expect(component.gameSize, size); - expect(component.gameRef, game); - }); + expect(component.gameSize, size); + expect(component.gameRef, game); + }, + ); test('prepare adds gameRef and calls onGameResize', () { final MyGame game = MyGame(); @@ -127,32 +129,34 @@ void main() { expect(game.components.contains(component), true); }); - flutter.testWidgets('component render and update is called', - (flutter.WidgetTester tester) async { - final MyGame game = MyGame(); - final MyComponent component = MyComponent(); + flutter.testWidgets( + 'component render and update is called', + (flutter.WidgetTester tester) async { + final MyGame game = MyGame(); + final MyComponent component = MyComponent(); - game.onResize(size); - game.add(component); - GameRenderBox renderBox; - tester.pumpWidget( - Builder( - builder: (BuildContext context) { - renderBox = GameRenderBox(context, game); - return GameWidget(game: game); - }, - ), - ); - renderBox.attach(PipelineOwner()); - renderBox.gameLoopCallback(1.0); - expect(component.isUpdateCalled, true); - renderBox.paint( - PaintingContext(ContainerLayer(), Rect.zero), - Offset.zero, - ); - expect(component.isRenderCalled, true); - renderBox.detach(); - }); + game.onResize(size); + game.add(component); + GameRenderBox renderBox; + tester.pumpWidget( + Builder( + builder: (BuildContext context) { + renderBox = GameRenderBox(context, game); + return GameWidget(game: game); + }, + ), + ); + renderBox.attach(PipelineOwner()); + renderBox.gameLoopCallback(1.0); + expect(component.isUpdateCalled, true); + renderBox.paint( + PaintingContext(ContainerLayer(), Rect.zero), + Offset.zero, + ); + expect(component.isRenderCalled, true); + renderBox.detach(); + }, + ); test('onRemove is only called once on component', () { final MyGame game = MyGame(); diff --git a/test/effects/combined_effect_test.dart b/test/effects/combined_effect_test.dart index e5dd7121c..e3112e492 100644 --- a/test/effects/combined_effect_test.dart +++ b/test/effects/combined_effect_test.dart @@ -107,20 +107,22 @@ void main() { }, ); - testWidgets('CombinedEffect alternation can peak', - (WidgetTester tester) async { - final PositionComponent positionComponent = component(); - effectTest( - tester, - positionComponent, - effect(isAlternating: true), - expectedPosition: path.last, - expectedAngle: argumentAngle, - expectedSize: argumentSize, - shouldComplete: false, - iterations: 0.5, - ); - }); + testWidgets( + 'CombinedEffect alternation can peak', + (WidgetTester tester) async { + final PositionComponent positionComponent = component(); + effectTest( + tester, + positionComponent, + effect(isAlternating: true), + expectedPosition: path.last, + expectedAngle: argumentAngle, + expectedSize: argumentSize, + shouldComplete: false, + iterations: 0.5, + ); + }, + ); testWidgets('CombinedEffect can be infinite', (WidgetTester tester) async { final PositionComponent positionComponent = component(); @@ -136,45 +138,51 @@ void main() { ); }); - testWidgets('CombinedEffect can contain alternating MoveEffect', - (WidgetTester tester) async { - final PositionComponent positionComponent = component(); - effectTest( - tester, - positionComponent, - effect(hasAlternatingMoveEffect: true), - expectedPosition: positionComponent.position.clone(), - expectedAngle: argumentAngle, - expectedSize: argumentSize, - shouldComplete: true, - ); - }); + testWidgets( + 'CombinedEffect can contain alternating MoveEffect', + (WidgetTester tester) async { + final PositionComponent positionComponent = component(); + effectTest( + tester, + positionComponent, + effect(hasAlternatingMoveEffect: true), + expectedPosition: positionComponent.position.clone(), + expectedAngle: argumentAngle, + expectedSize: argumentSize, + shouldComplete: true, + ); + }, + ); - testWidgets('CombinedEffect can contain alternating RotateEffect', - (WidgetTester tester) async { - final PositionComponent positionComponent = component(); - effectTest( - tester, - positionComponent, - effect(hasAlternatingRotateEffect: true), - expectedPosition: path.last, - expectedAngle: positionComponent.angle, - expectedSize: argumentSize, - shouldComplete: true, - ); - }); + testWidgets( + 'CombinedEffect can contain alternating RotateEffect', + (WidgetTester tester) async { + final PositionComponent positionComponent = component(); + effectTest( + tester, + positionComponent, + effect(hasAlternatingRotateEffect: true), + expectedPosition: path.last, + expectedAngle: positionComponent.angle, + expectedSize: argumentSize, + shouldComplete: true, + ); + }, + ); - testWidgets('CombinedEffect can contain alternating ScaleEffect', - (WidgetTester tester) async { - final PositionComponent positionComponent = component(); - effectTest( - tester, - positionComponent, - effect(hasAlternatingScaleEffect: true), - expectedPosition: path.last, - expectedAngle: argumentAngle, - expectedSize: positionComponent.size.clone(), - shouldComplete: true, - ); - }); + testWidgets( + 'CombinedEffect can contain alternating ScaleEffect', + (WidgetTester tester) async { + final PositionComponent positionComponent = component(); + effectTest( + tester, + positionComponent, + effect(hasAlternatingScaleEffect: true), + expectedPosition: path.last, + expectedAngle: argumentAngle, + expectedSize: positionComponent.size.clone(), + shouldComplete: true, + ); + }, + ); } diff --git a/test/effects/effect_test_utils.dart b/test/effects/effect_test_utils.dart index d271fcc07..dd8cf4034 100644 --- a/test/effects/effect_test_utils.dart +++ b/test/effects/effect_test_utils.dart @@ -87,8 +87,11 @@ void effectTest( ); } expect(effect.hasCompleted(), shouldComplete, reason: "Effect shouldFinish"); - expect(callback.isCalled, shouldComplete, - reason: "Callback was treated wrong"); + expect( + callback.isCalled, + shouldComplete, + reason: "Callback was treated wrong", + ); game.update(0.0); // Since effects are removed before they are updated expect(component.effects.isEmpty, shouldComplete); } diff --git a/test/effects/sequence_effect_test.dart b/test/effects/sequence_effect_test.dart index 160a5e81b..ad51c3a36 100644 --- a/test/effects/sequence_effect_test.dart +++ b/test/effects/sequence_effect_test.dart @@ -106,20 +106,22 @@ void main() { }, ); - testWidgets('SequenceEffect alternation can peak', - (WidgetTester tester) async { - final PositionComponent positionComponent = component(); - effectTest( - tester, - positionComponent, - effect(isAlternating: true), - expectedPosition: path.last, - expectedAngle: argumentAngle, - expectedSize: argumentSize, - shouldComplete: false, - iterations: 0.5, - ); - }); + testWidgets( + 'SequenceEffect alternation can peak', + (WidgetTester tester) async { + final PositionComponent positionComponent = component(); + effectTest( + tester, + positionComponent, + effect(isAlternating: true), + expectedPosition: path.last, + expectedAngle: argumentAngle, + expectedSize: argumentSize, + shouldComplete: false, + iterations: 0.5, + ); + }, + ); testWidgets('SequenceEffect can be infinite', (WidgetTester tester) async { final PositionComponent positionComponent = component(); @@ -135,45 +137,51 @@ void main() { ); }); - testWidgets('SequenceEffect can contain alternating MoveEffect', - (WidgetTester tester) async { - final PositionComponent positionComponent = component(); - effectTest( - tester, - positionComponent, - effect(hasAlternatingMoveEffect: true), - expectedPosition: positionComponent.position.clone(), - expectedAngle: argumentAngle, - expectedSize: argumentSize, - shouldComplete: true, - ); - }); + testWidgets( + 'SequenceEffect can contain alternating MoveEffect', + (WidgetTester tester) async { + final PositionComponent positionComponent = component(); + effectTest( + tester, + positionComponent, + effect(hasAlternatingMoveEffect: true), + expectedPosition: positionComponent.position.clone(), + expectedAngle: argumentAngle, + expectedSize: argumentSize, + shouldComplete: true, + ); + }, + ); - testWidgets('SequenceEffect can contain alternating RotateEffect', - (WidgetTester tester) async { - final PositionComponent positionComponent = component(); - effectTest( - tester, - positionComponent, - effect(hasAlternatingRotateEffect: true), - expectedPosition: path.last, - expectedAngle: positionComponent.angle, - expectedSize: argumentSize, - shouldComplete: true, - ); - }); + testWidgets( + 'SequenceEffect can contain alternating RotateEffect', + (WidgetTester tester) async { + final PositionComponent positionComponent = component(); + effectTest( + tester, + positionComponent, + effect(hasAlternatingRotateEffect: true), + expectedPosition: path.last, + expectedAngle: positionComponent.angle, + expectedSize: argumentSize, + shouldComplete: true, + ); + }, + ); - testWidgets('SequenceEffect can contain alternating ScaleEffect', - (WidgetTester tester) async { - final PositionComponent positionComponent = component(); - effectTest( - tester, - positionComponent, - effect(hasAlternatingScaleEffect: true), - expectedPosition: path.last, - expectedAngle: argumentAngle, - expectedSize: positionComponent.size.clone(), - shouldComplete: true, - ); - }); + testWidgets( + 'SequenceEffect can contain alternating ScaleEffect', + (WidgetTester tester) async { + final PositionComponent positionComponent = component(); + effectTest( + tester, + positionComponent, + effect(hasAlternatingScaleEffect: true), + expectedPosition: path.last, + expectedAngle: argumentAngle, + expectedSize: positionComponent.size.clone(), + shouldComplete: true, + ); + }, + ); }