From 7f2a29ffe47172a87f796427545e100e490cb58c Mon Sep 17 00:00:00 2001 From: arturplaczek Date: Thu, 28 Apr 2022 15:08:15 +0200 Subject: [PATCH 1/8] feat: create CharacterIcon --- .../widgets/character_icon.dart | 37 ++++++++++++++ .../widgets/character_icon_test.dart | 51 +++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 lib/select_character/widgets/character_icon.dart create mode 100644 test/select_character/widgets/character_icon_test.dart diff --git a/lib/select_character/widgets/character_icon.dart b/lib/select_character/widgets/character_icon.dart new file mode 100644 index 00000000..1afb4c6a --- /dev/null +++ b/lib/select_character/widgets/character_icon.dart @@ -0,0 +1,37 @@ +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:pinball/select_character/select_character.dart'; +import 'package:pinball_theme/pinball_theme.dart' hide Assets; + +class CharacterIcon extends StatelessWidget { + const CharacterIcon( + this.characterTheme, { + Key? key, + }) : super(key: key); + + final CharacterTheme characterTheme; + + @override + Widget build(BuildContext context) { + final currentCharacterTheme = + context.select( + (cubit) => cubit.state.characterTheme, + ); + + return GestureDetector( + onTap: () => + context.read().characterSelected(characterTheme), + child: Opacity( + opacity: currentCharacterTheme == characterTheme ? 1 : 0.5, + child: Padding( + padding: const EdgeInsets.all(8), + child: characterTheme.icon.image( + fit: BoxFit.contain, + ), + ), + ), + ); + } +} diff --git a/test/select_character/widgets/character_icon_test.dart b/test/select_character/widgets/character_icon_test.dart new file mode 100644 index 00000000..60dabba6 --- /dev/null +++ b/test/select_character/widgets/character_icon_test.dart @@ -0,0 +1,51 @@ +// ignore_for_file: prefer_const_constructors + +import 'package:bloc_test/bloc_test.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockingjay/mockingjay.dart'; +import 'package:pinball/select_character/select_character.dart'; +import 'package:pinball_theme/pinball_theme.dart'; + +import '../../helpers/helpers.dart'; + +void main() { + late CharacterThemeCubit characterThemeCubit; + + group('CharacterIcon', () { + setUp(() { + characterThemeCubit = MockCharacterThemeCubit(); + + whenListen( + characterThemeCubit, + const Stream.empty(), + initialState: const CharacterThemeState.initial(), + ); + }); + + testWidgets('renders character icon', (tester) async { + const characterTheme = DashTheme(); + + await tester.pumpApp( + const CharacterIcon(characterTheme), + characterThemeCubit: characterThemeCubit, + ); + + expect(find.image(characterTheme.icon), findsOneWidget); + }); + + testWidgets('tap on icon calls characterSelected on cubit', (tester) async { + const characterTheme = DashTheme(); + + await tester.pumpApp( + CharacterIcon(characterTheme), + characterThemeCubit: characterThemeCubit, + ); + + await tester.tap(find.byType(CharacterIcon)); + + verify( + () => characterThemeCubit.characterSelected(characterTheme), + ).called(1); + }); + }); +} From 6efcce46943cd6fa82b66593b5a7436685d8a5e1 Mon Sep 17 00:00:00 2001 From: arturplaczek Date: Thu, 28 Apr 2022 16:56:15 +0200 Subject: [PATCH 2/8] chore: create PinballButton --- lib/game/view/widgets/pinball_button.dart | 45 +++++++++++++++++++ .../view/widgets/pinball_button_test.dart | 39 ++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 lib/game/view/widgets/pinball_button.dart create mode 100644 test/game/view/widgets/pinball_button_test.dart diff --git a/lib/game/view/widgets/pinball_button.dart b/lib/game/view/widgets/pinball_button.dart new file mode 100644 index 00000000..fc739696 --- /dev/null +++ b/lib/game/view/widgets/pinball_button.dart @@ -0,0 +1,45 @@ +import 'package:flutter/material.dart'; +import 'package:pinball/gen/gen.dart'; + +/// {@template pinball_button} +/// Pinball button with onPressed [VoidCallback] and child [Widget]. +/// {@endtemplate} +class PinballButton extends StatelessWidget { + /// {@macro pinball_button} + const PinballButton({ + Key? key, + required this.child, + this.onPressed, + }) : super(key: key); + + /// Child displayed on button. + final Widget child; + + /// On pressed callback used for user integration. + final VoidCallback? onPressed; + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: onPressed, + child: DecoratedBox( + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage( + Assets.images.selectCharacter.pinballButton.keyName, + ), + ), + ), + child: Center( + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 32, + vertical: 16, + ), + child: child, + ), + ), + ), + ); + } +} diff --git a/test/game/view/widgets/pinball_button_test.dart b/test/game/view/widgets/pinball_button_test.dart new file mode 100644 index 00000000..50566dde --- /dev/null +++ b/test/game/view/widgets/pinball_button_test.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:pinball/game/game.dart'; + +import '../../../helpers/helpers.dart'; + +void main() { + const buttonText = 'this is the button text'; + + testWidgets('displays button', (tester) async { + await tester.pumpApp( + const Material( + child: PinballButton( + child: Text(buttonText), + ), + ), + ); + + expect(find.text(buttonText), findsOneWidget); + }); + + testWidgets('on tap calls onPressed callback', (tester) async { + var isTapped = false; + + await tester.pumpApp( + Material( + child: PinballButton( + child: const Text(buttonText), + onPressed: () { + isTapped = true; + }, + ), + ), + ); + await tester.tap(find.text(buttonText)); + + expect(isTapped, isTrue); + }); +} From c51ec65bf1728ffef8beb2efd4475b4fdc83bff5 Mon Sep 17 00:00:00 2001 From: arturplaczek Date: Thu, 28 Apr 2022 17:34:01 +0200 Subject: [PATCH 3/8] create: SelectedCharacter --- .../widgets/selected_character.dart | 98 +++++++++++++++++++ .../widgets/selected_character_test.dart | 46 +++++++++ 2 files changed, 144 insertions(+) create mode 100644 lib/select_character/widgets/selected_character.dart create mode 100644 test/select_character/widgets/selected_character_test.dart diff --git a/lib/select_character/widgets/selected_character.dart b/lib/select_character/widgets/selected_character.dart new file mode 100644 index 00000000..3b0fa9f2 --- /dev/null +++ b/lib/select_character/widgets/selected_character.dart @@ -0,0 +1,98 @@ +// ignore_for_file: public_member_api_docs + +import 'package:flame/flame.dart'; +import 'package:flame/sprite.dart'; +import 'package:flutter/material.dart' hide Image; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:pinball/select_character/select_character.dart'; +import 'package:pinball/theme/theme.dart'; +import 'package:pinball_flame/pinball_flame.dart'; +import 'package:pinball_theme/pinball_theme.dart'; + +class SelectedCharacter extends StatefulWidget { + const SelectedCharacter({ + Key? key, + }) : super(key: key); + + @override + State createState() => _SelectedCharacterState(); + + static List loadAssets() { + Flame.images.prefix = ''; + + const dashTheme = DashTheme(); + const androidTheme = AndroidTheme(); + const dinoTheme = DinoTheme(); + const sparkyTheme = SparkyTheme(); + + return [ + Flame.images.load(dashTheme.animation.keyName), + Flame.images.load(androidTheme.animation.keyName), + Flame.images.load(dinoTheme.animation.keyName), + Flame.images.load(sparkyTheme.animation.keyName), + Flame.images.load(dashTheme.background.keyName), + Flame.images.load(androidTheme.background.keyName), + Flame.images.load(dinoTheme.background.keyName), + Flame.images.load(sparkyTheme.background.keyName), + ]; + } +} + +class _SelectedCharacterState extends State + with TickerProviderStateMixin { + late SpriteAnimationController _controller; + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final currentCharacter = + context.select( + (cubit) => cubit.state.characterTheme, + ); + final spriteSheet = SpriteSheet.fromColumnsAndRows( + image: Flame.images.fromCache(currentCharacter.animation.keyName), + columns: 12, + rows: 6, + ); + final animation = spriteSheet.createAnimation( + row: 0, + stepTime: 1 / 24, + to: spriteSheet.rows * spriteSheet.columns, + ); + + _controller = SpriteAnimationController( + vsync: this, + animation: animation, + ); + + _controller + ..forward() + ..repeat(); + + return LayoutBuilder( + builder: (context, constraints) { + return ListView( + children: [ + Text( + currentCharacter.name, + style: AppTextStyle.headline3, + ), + const SizedBox(height: 20), + SizedBox( + width: constraints.maxWidth, + height: constraints.maxWidth, + child: SpriteAnimationWidget( + controller: _controller, + ), + ), + ], + ); + }, + ); + } +} diff --git a/test/select_character/widgets/selected_character_test.dart b/test/select_character/widgets/selected_character_test.dart new file mode 100644 index 00000000..8e379ebd --- /dev/null +++ b/test/select_character/widgets/selected_character_test.dart @@ -0,0 +1,46 @@ +// ignore_for_file: prefer_const_constructors + +import 'package:bloc_test/bloc_test.dart'; +import 'package:flame/flame.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:pinball/select_character/select_character.dart'; +import 'package:pinball_flame/pinball_flame.dart'; +import 'package:pinball_theme/pinball_theme.dart'; + +import '../../helpers/helpers.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + late CharacterThemeCubit characterThemeCubit; + + setUpAll(() async { + Flame.images.prefix = ''; + await Flame.images.load(const DashTheme().animation.keyName); + }); + + setUp(() async { + characterThemeCubit = MockCharacterThemeCubit(); + + whenListen( + characterThemeCubit, + Stream.value(const CharacterThemeState.initial()), + initialState: const CharacterThemeState.initial(), + ); + }); + + group('SelectedCharacter', () { + testWidgets('loadAssets returns list of futures', (tester) async { + expect(SelectedCharacter.loadAssets(), isList); + }); + + testWidgets('renders selected character', (tester) async { + await tester.pumpApp( + SelectedCharacter(), + characterThemeCubit: characterThemeCubit, + ); + await tester.pump(); + + expect(find.byType(SpriteAnimationWidget), findsOneWidget); + }); + }); +} From 80fec5e2a4f97aad6464649ad18f8138a7b6aa12 Mon Sep 17 00:00:00 2001 From: arturplaczek Date: Thu, 28 Apr 2022 17:46:35 +0200 Subject: [PATCH 4/8] chore: add assets --- .../select_character/pinball_button.png | Bin 0 -> 1602 bytes assets/images/select_character/star_a.png | Bin 0 -> 6684 bytes assets/images/select_character/star_b.png | Bin 0 -> 3690 bytes assets/images/select_character/star_c.png | Bin 0 -> 484 bytes lib/gen/assets.gen.dart | 22 ++++++++++++++++++ pubspec.yaml | 1 + 6 files changed, 23 insertions(+) create mode 100644 assets/images/select_character/pinball_button.png create mode 100644 assets/images/select_character/star_a.png create mode 100644 assets/images/select_character/star_b.png create mode 100644 assets/images/select_character/star_c.png diff --git a/assets/images/select_character/pinball_button.png b/assets/images/select_character/pinball_button.png new file mode 100644 index 0000000000000000000000000000000000000000..62373b857648faaf527a761891db0916811b6498 GIT binary patch literal 1602 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 literal 0 HcmV?d00001 diff --git a/assets/images/select_character/star_b.png b/assets/images/select_character/star_b.png new file mode 100644 index 0000000000000000000000000000000000000000..2832de06ab94ae381995205a6a592ec19f67f0e0 GIT binary patch literal 3690 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 B^ql|z literal 0 HcmV?d00001 diff --git a/assets/images/select_character/star_c.png b/assets/images/select_character/star_c.png new file mode 100644 index 0000000000000000000000000000000000000000..9e3135a8c7d7127c82807b211d2d61787c1b050f GIT binary patch literal 484 zcmeAS@N?(olHy`uVBq!ia0y~yU~&MmQ zL70(Y)*K0-;4x1Z$B>F!Z*O}BH8~2fCbFeY@|0v@5lI!<`Ty%3750k1?i)_M=aAg` zVpYewt4j`um`Auwl$22rm3+w4t#Rp~xXvOEX6^_VSLQ7(t|Bj!*t=J}5Ug!GMTSi<5LSiP`~(}14>j%yRK~~$SzH3@>Q@9tOKOB59S*`gZq bq@{jkzs^R3r3JfyK4S26^>bP0l+XkK@Vbgd literal 0 HcmV?d00001 diff --git a/lib/gen/assets.gen.dart b/lib/gen/assets.gen.dart index f5b935a5..2cc31a63 100644 --- a/lib/gen/assets.gen.dart +++ b/lib/gen/assets.gen.dart @@ -15,6 +15,8 @@ class $AssetsImagesGen { $AssetsImagesComponentsGen get components => const $AssetsImagesComponentsGen(); $AssetsImagesScoreGen get score => const $AssetsImagesScoreGen(); + $AssetsImagesSelectCharacterGen get selectCharacter => + const $AssetsImagesSelectCharacterGen(); } class $AssetsImagesBonusAnimationGen { @@ -57,6 +59,26 @@ class $AssetsImagesScoreGen { const AssetGenImage('assets/images/score/mini_score_background.png'); } +class $AssetsImagesSelectCharacterGen { + const $AssetsImagesSelectCharacterGen(); + + /// File path: assets/images/select_character/pinball_button.png + AssetGenImage get pinballButton => + const AssetGenImage('assets/images/select_character/pinball_button.png'); + + /// File path: assets/images/select_character/star_a.png + AssetGenImage get starA => + const AssetGenImage('assets/images/select_character/star_a.png'); + + /// File path: assets/images/select_character/star_b.png + AssetGenImage get starB => + const AssetGenImage('assets/images/select_character/star_b.png'); + + /// File path: assets/images/select_character/star_c.png + AssetGenImage get starC => + const AssetGenImage('assets/images/select_character/star_c.png'); +} + class Assets { Assets._(); diff --git a/pubspec.yaml b/pubspec.yaml index 48c570c3..61d36893 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -53,6 +53,7 @@ flutter: - assets/images/components/ - assets/images/bonus_animation/ - assets/images/score/ + - assets/images/select_character/ flutter_gen: line_length: 80 From 4ddce9550cab78f983cd457b63ab94dd3dcd47a2 Mon Sep 17 00:00:00 2001 From: arturplaczek Date: Thu, 28 Apr 2022 17:47:01 +0200 Subject: [PATCH 5/8] chore: create StarAnimation --- .../widgets/star_animation.dart | 84 +++++++++++++++++++ .../widgets/star_animation_test.dart | 44 ++++++++++ 2 files changed, 128 insertions(+) create mode 100644 lib/select_character/widgets/star_animation.dart create mode 100644 test/select_character/widgets/star_animation_test.dart diff --git a/lib/select_character/widgets/star_animation.dart b/lib/select_character/widgets/star_animation.dart new file mode 100644 index 00000000..0f23e336 --- /dev/null +++ b/lib/select_character/widgets/star_animation.dart @@ -0,0 +1,84 @@ +// ignore_for_file: public_member_api_docs + +import 'package:flame/flame.dart'; +import 'package:flame/sprite.dart'; +import 'package:flame/widgets.dart'; +import 'package:flutter/material.dart' hide Image; +import 'package:pinball/gen/gen.dart'; + +class StarAnimation extends StatelessWidget { + const StarAnimation._({ + Key? key, + required this.imagePath, + required this.columns, + required this.rows, + required this.stepTime, + }) : super(key: key); + + StarAnimation.starA({ + Key? key, + }) : this._( + key: key, + imagePath: Assets.images.selectCharacter.starA.keyName, + columns: 36, + rows: 2, + stepTime: 1 / 18, + ); + + StarAnimation.starB({ + Key? key, + }) : this._( + key: key, + imagePath: Assets.images.selectCharacter.starB.keyName, + columns: 36, + rows: 2, + stepTime: 1 / 36, + ); + + StarAnimation.starC({ + Key? key, + }) : this._( + key: key, + imagePath: Assets.images.selectCharacter.starC.keyName, + columns: 72, + rows: 1, + stepTime: 1 / 24, + ); + + final String imagePath; + final int columns; + final int rows; + final double stepTime; + + static Future loadAssets() { + Flame.images.prefix = ''; + + return Flame.images.loadAll([ + Assets.images.selectCharacter.starA.keyName, + Assets.images.selectCharacter.starB.keyName, + Assets.images.selectCharacter.starC.keyName, + ]); + } + + @override + Widget build(BuildContext context) { + final spriteSheet = SpriteSheet.fromColumnsAndRows( + image: Flame.images.fromCache(imagePath), + columns: columns, + rows: rows, + ); + final animation = spriteSheet.createAnimation( + row: 0, + stepTime: stepTime, + to: spriteSheet.rows * spriteSheet.columns, + ); + + return SizedBox( + width: 30, + height: 30, + child: SpriteAnimationWidget( + animation: animation, + ), + ); + } +} diff --git a/test/select_character/widgets/star_animation_test.dart b/test/select_character/widgets/star_animation_test.dart new file mode 100644 index 00000000..a743407f --- /dev/null +++ b/test/select_character/widgets/star_animation_test.dart @@ -0,0 +1,44 @@ +// ignore_for_file: invalid_use_of_protected_member + +import 'package:flame/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:pinball/select_character/select_character.dart'; + +import '../../helpers/helpers.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('loads SpriteAnimationWidget correctly for', () { + setUpAll(() async { + await StarAnimation.loadAssets(); + }); + + testWidgets('starA', (tester) async { + await tester.pumpApp( + StarAnimation.starA(), + ); + await tester.pump(); + + expect(find.byType(SpriteAnimationWidget), findsOneWidget); + }); + + testWidgets('starB', (tester) async { + await tester.pumpApp( + StarAnimation.starB(), + ); + await tester.pump(); + + expect(find.byType(SpriteAnimationWidget), findsOneWidget); + }); + + testWidgets('starC', (tester) async { + await tester.pumpApp( + StarAnimation.starC(), + ); + await tester.pump(); + + expect(find.byType(SpriteAnimationWidget), findsOneWidget); + }); + }); +} From 795d648850639118a441b62e3d1edba4cbb5e9e9 Mon Sep 17 00:00:00 2001 From: arturplaczek Date: Thu, 28 Apr 2022 17:47:25 +0200 Subject: [PATCH 6/8] chore: update barrel file --- lib/select_character/widgets/widgets.dart | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 lib/select_character/widgets/widgets.dart diff --git a/lib/select_character/widgets/widgets.dart b/lib/select_character/widgets/widgets.dart new file mode 100644 index 00000000..91f40a86 --- /dev/null +++ b/lib/select_character/widgets/widgets.dart @@ -0,0 +1,3 @@ +export 'character_icon.dart'; +export 'selected_character.dart'; +export 'star_animation.dart'; From 68c3233cef0c97d628c2bf3362f0fc75df95ccf1 Mon Sep 17 00:00:00 2001 From: arturplaczek Date: Thu, 28 Apr 2022 20:33:20 +0200 Subject: [PATCH 7/8] fix: update descriptions --- lib/game/view/widgets/pinball_button.dart | 21 +++++----- lib/game/view/widgets/widgets.dart | 1 + .../widgets/character_icon.dart | 25 +++++++---- .../widgets/selected_character.dart | 10 ++++- .../widgets/star_animation.dart | 41 ++++++++++++------- 5 files changed, 62 insertions(+), 36 deletions(-) diff --git a/lib/game/view/widgets/pinball_button.dart b/lib/game/view/widgets/pinball_button.dart index fc739696..db388ef1 100644 --- a/lib/game/view/widgets/pinball_button.dart +++ b/lib/game/view/widgets/pinball_button.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:pinball/gen/gen.dart'; +// TODO(arturplaczek): move PinballButton to pinball_ui + /// {@template pinball_button} /// Pinball button with onPressed [VoidCallback] and child [Widget]. /// {@endtemplate} @@ -8,20 +10,19 @@ class PinballButton extends StatelessWidget { /// {@macro pinball_button} const PinballButton({ Key? key, - required this.child, - this.onPressed, - }) : super(key: key); - - /// Child displayed on button. - final Widget child; + required Widget child, + VoidCallback? onPressed, + }) : _child = child, + _onPressed = onPressed, + super(key: key); - /// On pressed callback used for user integration. - final VoidCallback? onPressed; + final Widget _child; + final VoidCallback? _onPressed; @override Widget build(BuildContext context) { return InkWell( - onTap: onPressed, + onTap: _onPressed, child: DecoratedBox( decoration: BoxDecoration( image: DecorationImage( @@ -36,7 +37,7 @@ class PinballButton extends StatelessWidget { horizontal: 32, vertical: 16, ), - child: child, + child: _child, ), ), ), diff --git a/lib/game/view/widgets/widgets.dart b/lib/game/view/widgets/widgets.dart index 5d1fccf8..2bc78c9b 100644 --- a/lib/game/view/widgets/widgets.dart +++ b/lib/game/view/widgets/widgets.dart @@ -1,5 +1,6 @@ export 'bonus_animation.dart'; export 'game_hud.dart'; +export 'pinball_button.dart'; export 'play_button_overlay.dart'; export 'round_count_display.dart'; export 'score_view.dart'; diff --git a/lib/select_character/widgets/character_icon.dart b/lib/select_character/widgets/character_icon.dart index 1afb4c6a..aa697201 100644 --- a/lib/select_character/widgets/character_icon.dart +++ b/lib/select_character/widgets/character_icon.dart @@ -1,17 +1,23 @@ -// ignore_for_file: public_member_api_docs - import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:pinball/select_character/select_character.dart'; import 'package:pinball_theme/pinball_theme.dart' hide Assets; +/// {@template character_icon} +/// Widget for displaying character icon. +/// +/// On tap changes selected character in [CharacterThemeCubit]. +/// {@endtemplate} class CharacterIcon extends StatelessWidget { + /// {@macro character_icon} + const CharacterIcon( - this.characterTheme, { + CharacterTheme characterTheme, { Key? key, - }) : super(key: key); + }) : _characterTheme = characterTheme, + super(key: key); - final CharacterTheme characterTheme; + final CharacterTheme _characterTheme; @override Widget build(BuildContext context) { @@ -21,13 +27,14 @@ class CharacterIcon extends StatelessWidget { ); return GestureDetector( - onTap: () => - context.read().characterSelected(characterTheme), + onTap: () => context + .read() + .characterSelected(_characterTheme), child: Opacity( - opacity: currentCharacterTheme == characterTheme ? 1 : 0.5, + opacity: currentCharacterTheme == _characterTheme ? 1 : 0.5, child: Padding( padding: const EdgeInsets.all(8), - child: characterTheme.icon.image( + child: _characterTheme.icon.image( fit: BoxFit.contain, ), ), diff --git a/lib/select_character/widgets/selected_character.dart b/lib/select_character/widgets/selected_character.dart index 3b0fa9f2..0e9dd430 100644 --- a/lib/select_character/widgets/selected_character.dart +++ b/lib/select_character/widgets/selected_character.dart @@ -1,5 +1,3 @@ -// ignore_for_file: public_member_api_docs - import 'package:flame/flame.dart'; import 'package:flame/sprite.dart'; import 'package:flutter/material.dart' hide Image; @@ -9,7 +7,14 @@ import 'package:pinball/theme/theme.dart'; import 'package:pinball_flame/pinball_flame.dart'; import 'package:pinball_theme/pinball_theme.dart'; +/// {@template selected_character} +/// Widget to display the selected character based on the [CharacterThemeCubit] +/// state. +/// +/// Displays a looped [SpriteAnimationWidget]. +/// {@endtemplate} class SelectedCharacter extends StatefulWidget { + /// {@macro selected_character} const SelectedCharacter({ Key? key, }) : super(key: key); @@ -17,6 +22,7 @@ class SelectedCharacter extends StatefulWidget { @override State createState() => _SelectedCharacterState(); + /// Returns a list of assets to be loaded static List loadAssets() { Flame.images.prefix = ''; diff --git a/lib/select_character/widgets/star_animation.dart b/lib/select_character/widgets/star_animation.dart index 0f23e336..662420fb 100644 --- a/lib/select_character/widgets/star_animation.dart +++ b/lib/select_character/widgets/star_animation.dart @@ -1,20 +1,28 @@ -// ignore_for_file: public_member_api_docs - import 'package:flame/flame.dart'; import 'package:flame/sprite.dart'; import 'package:flame/widgets.dart'; import 'package:flutter/material.dart' hide Image; import 'package:pinball/gen/gen.dart'; +/// {@template star_animation} +/// Widget to display a looped the star animation. +/// +/// For animation is using [SpriteAnimationWidget]. +/// {@endtemplate} class StarAnimation extends StatelessWidget { const StarAnimation._({ Key? key, - required this.imagePath, - required this.columns, - required this.rows, - required this.stepTime, - }) : super(key: key); + required String imagePath, + required int columns, + required int rows, + required double stepTime, + }) : _imagePath = imagePath, + _columns = columns, + _rows = rows, + _stepTime = stepTime, + super(key: key); + /// [Widget] that displays the star A animation. StarAnimation.starA({ Key? key, }) : this._( @@ -25,6 +33,7 @@ class StarAnimation extends StatelessWidget { stepTime: 1 / 18, ); + /// [Widget] that displays the star B animation. StarAnimation.starB({ Key? key, }) : this._( @@ -35,6 +44,7 @@ class StarAnimation extends StatelessWidget { stepTime: 1 / 36, ); + /// [Widget] that displays the star C animation. StarAnimation.starC({ Key? key, }) : this._( @@ -45,11 +55,12 @@ class StarAnimation extends StatelessWidget { stepTime: 1 / 24, ); - final String imagePath; - final int columns; - final int rows; - final double stepTime; + final String _imagePath; + final int _columns; + final int _rows; + final double _stepTime; + /// Returns a list of assets to be loaded static Future loadAssets() { Flame.images.prefix = ''; @@ -63,13 +74,13 @@ class StarAnimation extends StatelessWidget { @override Widget build(BuildContext context) { final spriteSheet = SpriteSheet.fromColumnsAndRows( - image: Flame.images.fromCache(imagePath), - columns: columns, - rows: rows, + image: Flame.images.fromCache(_imagePath), + columns: _columns, + rows: _rows, ); final animation = spriteSheet.createAnimation( row: 0, - stepTime: stepTime, + stepTime: _stepTime, to: spriteSheet.rows * spriteSheet.columns, ); From ca1317231284a8ae7ea2cac8923a0696dd756fb8 Mon Sep 17 00:00:00 2001 From: arturplaczek Date: Thu, 28 Apr 2022 20:46:00 +0200 Subject: [PATCH 8/8] fix: apply self review --- lib/select_character/select_character.dart | 1 + lib/select_character/widgets/character_icon.dart | 3 +-- lib/select_character/widgets/selected_character.dart | 5 +++-- lib/select_character/widgets/star_animation.dart | 4 ++-- test/select_character/widgets/selected_character_test.dart | 3 ++- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/select_character/select_character.dart b/lib/select_character/select_character.dart index 40699840..827be100 100644 --- a/lib/select_character/select_character.dart +++ b/lib/select_character/select_character.dart @@ -1,2 +1,3 @@ export 'cubit/character_theme_cubit.dart'; export 'view/view.dart'; +export 'widgets/widgets.dart'; diff --git a/lib/select_character/widgets/character_icon.dart b/lib/select_character/widgets/character_icon.dart index aa697201..3da77903 100644 --- a/lib/select_character/widgets/character_icon.dart +++ b/lib/select_character/widgets/character_icon.dart @@ -4,13 +4,12 @@ import 'package:pinball/select_character/select_character.dart'; import 'package:pinball_theme/pinball_theme.dart' hide Assets; /// {@template character_icon} -/// Widget for displaying character icon. +/// Widget to display character icon. /// /// On tap changes selected character in [CharacterThemeCubit]. /// {@endtemplate} class CharacterIcon extends StatelessWidget { /// {@macro character_icon} - const CharacterIcon( CharacterTheme characterTheme, { Key? key, diff --git a/lib/select_character/widgets/selected_character.dart b/lib/select_character/widgets/selected_character.dart index 0e9dd430..0b6fc758 100644 --- a/lib/select_character/widgets/selected_character.dart +++ b/lib/select_character/widgets/selected_character.dart @@ -11,7 +11,8 @@ import 'package:pinball_theme/pinball_theme.dart'; /// Widget to display the selected character based on the [CharacterThemeCubit] /// state. /// -/// Displays a looped [SpriteAnimationWidget]. +/// Displays the looped [SpriteAnimationWidget] and the character name on the +/// list. /// {@endtemplate} class SelectedCharacter extends StatefulWidget { /// {@macro selected_character} @@ -22,7 +23,7 @@ class SelectedCharacter extends StatefulWidget { @override State createState() => _SelectedCharacterState(); - /// Returns a list of assets to be loaded + /// Returns a list of assets to be loaded. static List loadAssets() { Flame.images.prefix = ''; diff --git a/lib/select_character/widgets/star_animation.dart b/lib/select_character/widgets/star_animation.dart index 662420fb..62b0de4a 100644 --- a/lib/select_character/widgets/star_animation.dart +++ b/lib/select_character/widgets/star_animation.dart @@ -7,7 +7,7 @@ import 'package:pinball/gen/gen.dart'; /// {@template star_animation} /// Widget to display a looped the star animation. /// -/// For animation is using [SpriteAnimationWidget]. +/// For animation uses [SpriteAnimationWidget]. /// {@endtemplate} class StarAnimation extends StatelessWidget { const StarAnimation._({ @@ -60,7 +60,7 @@ class StarAnimation extends StatelessWidget { final int _rows; final double _stepTime; - /// Returns a list of assets to be loaded + /// Returns a list of assets to be loaded. static Future loadAssets() { Flame.images.prefix = ''; diff --git a/test/select_character/widgets/selected_character_test.dart b/test/select_character/widgets/selected_character_test.dart index 8e379ebd..70ccf3fc 100644 --- a/test/select_character/widgets/selected_character_test.dart +++ b/test/select_character/widgets/selected_character_test.dart @@ -11,6 +11,7 @@ import '../../helpers/helpers.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); + late CharacterThemeCubit characterThemeCubit; setUpAll(() async { @@ -29,7 +30,7 @@ void main() { }); group('SelectedCharacter', () { - testWidgets('loadAssets returns list of futures', (tester) async { + testWidgets('loadAssets method returns list of futures', (tester) async { expect(SelectedCharacter.loadAssets(), isList); });