From 8f877ab158c674ccb5a5a10216efa41ad82397ae Mon Sep 17 00:00:00 2001 From: arturplaczek Date: Thu, 28 Apr 2022 12:19:38 +0200 Subject: [PATCH 1/9] chore: move StartGameBloc over the app --- lib/app/view/app.dart | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/app/view/app.dart b/lib/app/view/app.dart index 97cfec9b..8165b2f4 100644 --- a/lib/app/view/app.dart +++ b/lib/app/view/app.dart @@ -14,6 +14,7 @@ import 'package:leaderboard_repository/leaderboard_repository.dart'; import 'package:pinball/game/game.dart'; import 'package:pinball/l10n/l10n.dart'; import 'package:pinball/select_character/select_character.dart'; +import 'package:pinball/start_game/start_game.dart'; import 'package:pinball_audio/pinball_audio.dart'; class App extends StatelessWidget { @@ -35,8 +36,11 @@ class App extends StatelessWidget { RepositoryProvider.value(value: _leaderboardRepository), RepositoryProvider.value(value: _pinballAudio), ], - child: BlocProvider( - create: (context) => CharacterThemeCubit(), + child: MultiBlocProvider( + providers: [ + BlocProvider(create: (context) => CharacterThemeCubit()), + BlocProvider(create: (context) => StartGameBloc()), + ], child: const MaterialApp( title: 'I/O Pinball', localizationsDelegates: [ From 643fa45839b4d1a35f77936fc7d7c0aa1dad5136 Mon Sep 17 00:00:00 2001 From: arturplaczek Date: Thu, 28 Apr 2022 12:20:52 +0200 Subject: [PATCH 2/9] chore: remove pinballGame from StartGameBloc --- lib/start_game/bloc/start_game_bloc.dart | 10 +--------- test/start_game/bloc/start_game_bloc_test.dart | 12 +++--------- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/lib/start_game/bloc/start_game_bloc.dart b/lib/start_game/bloc/start_game_bloc.dart index ba44d88c..3a96b57b 100644 --- a/lib/start_game/bloc/start_game_bloc.dart +++ b/lib/start_game/bloc/start_game_bloc.dart @@ -1,6 +1,5 @@ import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; -import 'package:pinball/game/game.dart'; part 'start_game_event.dart'; part 'start_game_state.dart'; @@ -10,23 +9,16 @@ part 'start_game_state.dart'; /// {@endtemplate} class StartGameBloc extends Bloc { /// {@macro start_game_bloc} - StartGameBloc({ - required PinballGame game, - }) : _game = game, - super(const StartGameState.initial()) { + StartGameBloc() : super(const StartGameState.initial()) { on(_onPlayTapped); on(_onCharacterSelected); on(_onHowToPlayFinished); } - final PinballGame _game; - void _onPlayTapped( PlayTapped event, Emitter emit, ) { - _game.gameFlowController.start(); - emit( state.copyWith( status: StartGameStatus.selectCharacter, diff --git a/test/start_game/bloc/start_game_bloc_test.dart b/test/start_game/bloc/start_game_bloc_test.dart index ec1b3ced..0300d1f0 100644 --- a/test/start_game/bloc/start_game_bloc_test.dart +++ b/test/start_game/bloc/start_game_bloc_test.dart @@ -22,9 +22,7 @@ void main() { group('StartGameBloc', () { blocTest( 'on PlayTapped changes status to selectCharacter', - build: () => StartGameBloc( - game: pinballGame, - ), + build: StartGameBloc.new, act: (bloc) => bloc.add(const PlayTapped()), expect: () => [ const StartGameState( @@ -35,9 +33,7 @@ void main() { blocTest( 'on CharacterSelected changes status to howToPlay', - build: () => StartGameBloc( - game: pinballGame, - ), + build: StartGameBloc.new, act: (bloc) => bloc.add(const CharacterSelected()), expect: () => [ const StartGameState( @@ -48,9 +44,7 @@ void main() { blocTest( 'on HowToPlayFinished changes status to play', - build: () => StartGameBloc( - game: pinballGame, - ), + build: StartGameBloc.new, act: (bloc) => bloc.add(const HowToPlayFinished()), expect: () => [ const StartGameState( From ffb931e4c2de096673ea1a631577db5151c6f99e Mon Sep 17 00:00:00 2001 From: arturplaczek Date: Thu, 28 Apr 2022 12:22:06 +0200 Subject: [PATCH 3/9] chore: remove pinballGame from PlayButtonOverlay --- .../view/widgets/play_button_overlay.dart | 29 +++------------ .../widgets/play_button_overlay_test.dart | 36 +++++++++---------- 2 files changed, 20 insertions(+), 45 deletions(-) diff --git a/lib/game/view/widgets/play_button_overlay.dart b/lib/game/view/widgets/play_button_overlay.dart index f90ebb98..21493ca2 100644 --- a/lib/game/view/widgets/play_button_overlay.dart +++ b/lib/game/view/widgets/play_button_overlay.dart @@ -1,20 +1,14 @@ import 'package:flutter/material.dart'; -import 'package:pinball/game/pinball_game.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:pinball/l10n/l10n.dart'; -import 'package:pinball/select_character/select_character.dart'; +import 'package:pinball/start_game/start_game.dart'; /// {@template play_button_overlay} /// [Widget] that renders the button responsible to starting the game /// {@endtemplate} class PlayButtonOverlay extends StatelessWidget { /// {@macro play_button_overlay} - const PlayButtonOverlay({ - Key? key, - required PinballGame game, - }) : _game = game, - super(key: key); - - final PinballGame _game; + const PlayButtonOverlay({Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -23,22 +17,7 @@ class PlayButtonOverlay extends StatelessWidget { return Center( child: ElevatedButton( onPressed: () { - _game.gameFlowController.start(); - showDialog( - context: context, - barrierDismissible: false, - builder: (_) { - final height = MediaQuery.of(context).size.height * 0.5; - - return Center( - child: SizedBox( - height: height, - width: height * 1.4, - child: const CharacterSelectionDialog(), - ), - ); - }, - ); + context.read().add(const PlayTapped()); }, child: Text(l10n.play), ), diff --git a/test/game/view/widgets/play_button_overlay_test.dart b/test/game/view/widgets/play_button_overlay_test.dart index 0345978d..10277dee 100644 --- a/test/game/view/widgets/play_button_overlay_test.dart +++ b/test/game/view/widgets/play_button_overlay_test.dart @@ -1,46 +1,42 @@ +import 'package:bloc_test/bloc_test.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; import 'package:pinball/game/game.dart'; -import 'package:pinball/select_character/select_character.dart'; +import 'package:pinball/start_game/bloc/start_game_bloc.dart'; import '../../../helpers/helpers.dart'; void main() { group('PlayButtonOverlay', () { - late PinballGame game; - late GameFlowController gameFlowController; + late StartGameBloc startGameBloc; setUp(() { - game = MockPinballGame(); - gameFlowController = MockGameFlowController(); + startGameBloc = MockStartGameBloc(); - when(() => game.gameFlowController).thenReturn(gameFlowController); - when(gameFlowController.start).thenAnswer((_) {}); + whenListen( + startGameBloc, + Stream.value(const StartGameState.initial()), + initialState: const StartGameState.initial(), + ); }); testWidgets('renders correctly', (tester) async { - await tester.pumpApp(PlayButtonOverlay(game: game)); + await tester.pumpApp(const PlayButtonOverlay()); expect(find.text('Play'), findsOneWidget); }); - testWidgets('calls gameFlowController.start when taped', (tester) async { - await tester.pumpApp(PlayButtonOverlay(game: game)); - - await tester.tap(find.text('Play')); - await tester.pump(); - - verify(gameFlowController.start).called(1); - }); - - testWidgets('displays CharacterSelectionDialog when tapped', + testWidgets('calls PlayTapped event to StartGameBloc when taped on play', (tester) async { - await tester.pumpApp(PlayButtonOverlay(game: game)); + await tester.pumpApp( + const PlayButtonOverlay(), + startGameBloc: startGameBloc, + ); await tester.tap(find.text('Play')); await tester.pump(); - expect(find.byType(CharacterSelectionDialog), findsOneWidget); + verify(() => startGameBloc.add(const PlayTapped())).called(1); }); }); } From d54beef599dc8c5f47d565caf923b6c5d32225e5 Mon Sep 17 00:00:00 2001 From: arturplaczek Date: Thu, 28 Apr 2022 12:24:25 +0200 Subject: [PATCH 4/9] chore: create StartGameListener --- .../widgets/start_game_listener.dart | 85 +++++++++ .../widgets/start_game_listener_test.dart | 178 ++++++++++++++++++ 2 files changed, 263 insertions(+) create mode 100644 lib/start_game/widgets/start_game_listener.dart create mode 100644 test/start_game/widgets/start_game_listener_test.dart diff --git a/lib/start_game/widgets/start_game_listener.dart b/lib/start_game/widgets/start_game_listener.dart new file mode 100644 index 00000000..466c3c39 --- /dev/null +++ b/lib/start_game/widgets/start_game_listener.dart @@ -0,0 +1,85 @@ +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:pinball/game/game.dart'; +import 'package:pinball/select_character/select_character.dart'; +import 'package:pinball/start_game/start_game.dart'; +import 'package:pinball/theme/theme.dart'; + +class StartGameListener extends StatelessWidget { + const StartGameListener({ + Key? key, + required Widget child, + required PinballGame game, + }) : _child = child, + _game = game, + super(key: key); + + final Widget _child; + final PinballGame _game; + + @override + Widget build(BuildContext context) { + return BlocListener( + listener: (context, state) { + switch (state.status) { + case StartGameStatus.selectCharacter: + _onSelectCharacter(context); + break; + case StartGameStatus.howToPlay: + _handleHowToPlay(context); + break; + case StartGameStatus.play: + _game.gameFlowController.start(); + break; + case StartGameStatus.initial: + break; + } + }, + child: _child, + ); + } + + void _onSelectCharacter( + BuildContext context, + ) { + showDialog( + context: context, + builder: (_) { + // TODO(arturplaczek): remove that when PR with PinballLayout will be + // merged + final height = MediaQuery.of(context).size.height * 0.5; + + return Center( + child: SizedBox( + height: height, + width: height * 1.2, + child: const CharacterSelectionDialog(), + ), + ); + }, + barrierDismissible: false, + ); + } +} + +Future _handleHowToPlay( + BuildContext context, +) async { + final startGameBloc = context.read(); + + await showDialog( + context: context, + barrierColor: AppColors.transparent, + builder: (_) { + return Center( + child: HowToPlayDialog( + onDismissCallback: () { + startGameBloc.add(const HowToPlayFinished()); + }, + ), + ); + }, + ); +} diff --git a/test/start_game/widgets/start_game_listener_test.dart b/test/start_game/widgets/start_game_listener_test.dart new file mode 100644 index 00000000..e35cef78 --- /dev/null +++ b/test/start_game/widgets/start_game_listener_test.dart @@ -0,0 +1,178 @@ +import 'package:bloc_test/bloc_test.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:pinball/game/game.dart'; +import 'package:pinball/select_character/select_character.dart'; +import 'package:pinball/start_game/start_game.dart'; + +import '../../helpers/helpers.dart'; + +void main() { + late StartGameBloc startGameBloc; + late PinballGame pinballGame; + + group('StartGameListener', () { + setUp(() { + startGameBloc = MockStartGameBloc(); + pinballGame = MockPinballGame(); + }); + + testWidgets( + 'on selectCharacter status shows SelectCharacter dialog', + (tester) async { + whenListen( + startGameBloc, + Stream.value( + const StartGameState(status: StartGameStatus.selectCharacter), + ), + initialState: const StartGameState.initial(), + ); + + await tester.pumpApp( + StartGameListener( + game: pinballGame, + child: const SizedBox.shrink(), + ), + startGameBloc: startGameBloc, + ); + + await tester.pumpAndSettle(); + + expect( + find.byType(CharacterSelectionDialog), + findsOneWidget, + ); + }, + ); + + testWidgets( + 'on howToPlay status shows HowToPlay dialog', + (tester) async { + whenListen( + startGameBloc, + Stream.value( + const StartGameState(status: StartGameStatus.howToPlay), + ), + initialState: const StartGameState.initial(), + ); + + await tester.pumpApp( + StartGameListener( + game: pinballGame, + child: const SizedBox.shrink(), + ), + startGameBloc: startGameBloc, + ); + + await tester.pumpAndSettle(); + + expect( + find.byType(HowToPlayDialog), + findsOneWidget, + ); + }, + ); + + testWidgets( + 'on play status call start on game controller', + (tester) async { + whenListen( + startGameBloc, + Stream.value( + const StartGameState(status: StartGameStatus.play), + ), + initialState: const StartGameState.initial(), + ); + + final gameController = MockGameFlowController(); + when(() => pinballGame.gameFlowController) + .thenAnswer((invocation) => gameController); + + await tester.pumpApp( + StartGameListener( + game: pinballGame, + child: const SizedBox.shrink(), + ), + startGameBloc: startGameBloc, + ); + + await tester.pumpAndSettle(kThemeAnimationDuration); + await tester.pumpAndSettle(kThemeAnimationDuration); + + verify(gameController.start).called(1); + }, + ); + + testWidgets( + 'do nothing on initial status', + (tester) async { + whenListen( + startGameBloc, + Stream.value( + const StartGameState(status: StartGameStatus.initial), + ), + initialState: const StartGameState.initial(), + ); + + await tester.pumpApp( + StartGameListener( + game: pinballGame, + child: const SizedBox.shrink(), + ), + startGameBloc: startGameBloc, + ); + + await tester.pumpAndSettle(); + + expect( + find.byType(HowToPlayDialog), + findsNothing, + ); + expect( + find.byType(CharacterSelectionDialog), + findsNothing, + ); + }, + ); + + testWidgets( + 'calls HowToPlayFinished event after HowToPlayDialog is closed', + (tester) async { + whenListen( + startGameBloc, + Stream.value( + const StartGameState(status: StartGameStatus.howToPlay), + ), + initialState: const StartGameState.initial(), + ); + + await tester.pumpApp( + StartGameListener( + game: pinballGame, + child: const SizedBox.shrink(), + ), + startGameBloc: startGameBloc, + ); + await tester.pumpAndSettle(); + + expect( + find.byType(HowToPlayDialog), + findsOneWidget, + ); + await tester.tapAt(const Offset(1, 1)); + await tester.pumpAndSettle(); + + expect( + find.byType(HowToPlayDialog), + findsNothing, + ); + await tester.pumpAndSettle(); + + verify( + () => startGameBloc.add(const HowToPlayFinished()), + ).called(1); + }, + ); + }); +} From 3f150c77a368538acd1dc81ad50ac00659c8b65e Mon Sep 17 00:00:00 2001 From: arturplaczek Date: Thu, 28 Apr 2022 12:25:02 +0200 Subject: [PATCH 5/9] chore: add on dismiss callback to HowToPlayDialog --- .../widgets/how_to_play_dialog.dart | 41 +++++++++++++------ .../widgets/how_to_play_dialog_test.dart | 6 ++- 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/lib/start_game/widgets/how_to_play_dialog.dart b/lib/start_game/widgets/how_to_play_dialog.dart index aed7a3e3..2f32085f 100644 --- a/lib/start_game/widgets/how_to_play_dialog.dart +++ b/lib/start_game/widgets/how_to_play_dialog.dart @@ -4,25 +4,40 @@ import 'package:flutter/material.dart'; import 'package:pinball/l10n/l10n.dart'; class HowToPlayDialog extends StatelessWidget { - const HowToPlayDialog({Key? key}) : super(key: key); + const HowToPlayDialog({ + Key? key, + required this.onDismissCallback, + }) : super(key: key); + + final VoidCallback onDismissCallback; @override Widget build(BuildContext context) { final l10n = context.l10n; const spacing = SizedBox(height: 16); - return Dialog( - child: Padding( - padding: const EdgeInsets.all(20), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text(l10n.howToPlay), - spacing, - const _LaunchControls(), - spacing, - const _FlipperControls(), - ], + return WillPopScope( + onWillPop: () { + Future.delayed( + kThemeAnimationDuration, + onDismissCallback.call, + ); + + return Future.value(true); + }, + child: Dialog( + child: Padding( + padding: const EdgeInsets.all(20), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text(l10n.howToPlay), + spacing, + const _LaunchControls(), + spacing, + const _FlipperControls(), + ], + ), ), ), ); diff --git a/test/start_game/widgets/how_to_play_dialog_test.dart b/test/start_game/widgets/how_to_play_dialog_test.dart index 082f102e..ee6277f4 100644 --- a/test/start_game/widgets/how_to_play_dialog_test.dart +++ b/test/start_game/widgets/how_to_play_dialog_test.dart @@ -9,7 +9,11 @@ import '../../helpers/helpers.dart'; void main() { group('HowToPlayDialog', () { testWidgets('displays dialog', (tester) async { - await tester.pumpApp(HowToPlayDialog()); + await tester.pumpApp( + HowToPlayDialog( + onDismissCallback: () {}, + ), + ); expect(find.byType(Dialog), findsOneWidget); }); From 8eba4ccc6ba216d25cd5cd52813dff54dbd01b99 Mon Sep 17 00:00:00 2001 From: arturplaczek Date: Thu, 28 Apr 2022 12:25:27 +0200 Subject: [PATCH 6/9] chore: update CharacterSelectionDialog --- .../view/character_selection_page.dart | 5 +---- .../view/character_selection_page_test.dart | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/lib/select_character/view/character_selection_page.dart b/lib/select_character/view/character_selection_page.dart index 0e83db8d..5a832cf9 100644 --- a/lib/select_character/view/character_selection_page.dart +++ b/lib/select_character/view/character_selection_page.dart @@ -48,10 +48,7 @@ class CharacterSelectionView extends StatelessWidget { TextButton( onPressed: () { Navigator.of(context).pop(); - showDialog( - context: context, - builder: (_) => const HowToPlayDialog(), - ); + context.read().add(const CharacterSelected()); }, child: Text(l10n.start), ), diff --git a/test/select_character/view/character_selection_page_test.dart b/test/select_character/view/character_selection_page_test.dart index 0dda92d7..2debdb3f 100644 --- a/test/select_character/view/character_selection_page_test.dart +++ b/test/select_character/view/character_selection_page_test.dart @@ -12,9 +12,12 @@ import '../../helpers/helpers.dart'; void main() { late CharacterThemeCubit characterThemeCubit; + late StartGameBloc startGameBloc; setUp(() { characterThemeCubit = MockCharacterThemeCubit(); + startGameBloc = MockStartGameBloc(); + whenListen( characterThemeCubit, const Stream.empty(), @@ -84,17 +87,24 @@ void main() { .called(1); }); - testWidgets('displays how to play dialog when start is tapped', + testWidgets('calls CharacterSelected event when start is tapped', (tester) async { + whenListen( + startGameBloc, + Stream.value(const StartGameState.initial()), + initialState: const StartGameState.initial(), + ); + await tester.pumpApp( CharacterSelectionView(), characterThemeCubit: characterThemeCubit, + startGameBloc: startGameBloc, ); await tester.ensureVisible(find.byType(TextButton)); await tester.tap(find.byType(TextButton)); await tester.pumpAndSettle(); - expect(find.byType(HowToPlayDialog), findsOneWidget); + verify(() => startGameBloc.add(CharacterSelected())).called(1); }); }); From 0840a31e038e00482ec221dc6385f2e9dc6468bc Mon Sep 17 00:00:00 2001 From: arturplaczek Date: Thu, 28 Apr 2022 12:25:41 +0200 Subject: [PATCH 7/9] chore: update PinballGamePage --- lib/game/view/pinball_game_page.dart | 56 +++++++++++++++------------- lib/start_game/widgets/widgets.dart | 1 + 2 files changed, 32 insertions(+), 25 deletions(-) diff --git a/lib/game/view/pinball_game_page.dart b/lib/game/view/pinball_game_page.dart index be11a15c..2fd10424 100644 --- a/lib/game/view/pinball_game_page.dart +++ b/lib/game/view/pinball_game_page.dart @@ -48,7 +48,6 @@ class PinballGamePage extends StatelessWidget { return MultiBlocProvider( providers: [ - BlocProvider(create: (_) => StartGameBloc(game: game)), BlocProvider(create: (_) => GameBloc()), BlocProvider( create: (_) => AssetsManagerCubit(loadables)..load(), @@ -114,36 +113,43 @@ class PinballGameLoadedView extends StatelessWidget { @override Widget build(BuildContext context) { + final isPlaying = context.select( + (StartGameBloc bloc) => bloc.state.status == StartGameStatus.play, + ); final gameWidgetWidth = MediaQuery.of(context).size.height * 9 / 16; final screenWidth = MediaQuery.of(context).size.width; final leftMargin = (screenWidth / 2) - (gameWidgetWidth / 1.8); - return Stack( - children: [ - Positioned.fill( - child: GameWidget( - game: game, - initialActiveOverlays: const [PinballGame.playButtonOverlay], - overlayBuilderMap: { - PinballGame.playButtonOverlay: (context, game) { - return Positioned( - bottom: 20, - right: 0, - left: 0, - child: PlayButtonOverlay(game: game), - ); + return StartGameListener( + game: game, + child: Stack( + children: [ + Positioned.fill( + child: GameWidget( + game: game, + initialActiveOverlays: const [PinballGame.playButtonOverlay], + overlayBuilderMap: { + PinballGame.playButtonOverlay: (context, game) { + return const Positioned( + bottom: 20, + right: 0, + left: 0, + child: PlayButtonOverlay(), + ); + }, }, - }, + ), ), - ), - // TODO(arturplaczek): add Visibility to GameHud based on StartGameBloc - // status - Positioned( - top: 16, - left: leftMargin, - child: const GameHud(), - ), - ], + Positioned( + top: 16, + left: leftMargin, + child: Visibility( + visible: isPlaying, + child: const GameHud(), + ), + ), + ], + ), ); } } diff --git a/lib/start_game/widgets/widgets.dart b/lib/start_game/widgets/widgets.dart index bad2c6b5..fa7c7253 100644 --- a/lib/start_game/widgets/widgets.dart +++ b/lib/start_game/widgets/widgets.dart @@ -1 +1,2 @@ export 'how_to_play_dialog.dart'; +export 'start_game_listener.dart'; From d8ffa0693fae3205a61aa86b865d4d4992cb0c40 Mon Sep 17 00:00:00 2001 From: arturplaczek Date: Thu, 28 Apr 2022 15:39:42 +0200 Subject: [PATCH 8/9] fix: apply self review --- .../widgets/how_to_play_dialog.dart | 21 ++----- .../widgets/start_game_listener.dart | 59 ++++++++++--------- test/game/view/pinball_game_page_test.dart | 11 ++-- .../widgets/start_game_listener_test.dart | 2 +- 4 files changed, 43 insertions(+), 50 deletions(-) diff --git a/lib/start_game/widgets/how_to_play_dialog.dart b/lib/start_game/widgets/how_to_play_dialog.dart index 2f32085f..f1d11248 100644 --- a/lib/start_game/widgets/how_to_play_dialog.dart +++ b/lib/start_game/widgets/how_to_play_dialog.dart @@ -18,18 +18,13 @@ class HowToPlayDialog extends StatelessWidget { return WillPopScope( onWillPop: () { - Future.delayed( - kThemeAnimationDuration, - onDismissCallback.call, - ); - + onDismissCallback.call(); return Future.value(true); }, child: Dialog( child: Padding( padding: const EdgeInsets.all(20), - child: Column( - mainAxisSize: MainAxisSize.min, + child: ListView( children: [ Text(l10n.howToPlay), spacing, @@ -56,9 +51,7 @@ class _LaunchControls extends StatelessWidget { children: [ Text(l10n.launchControls), const SizedBox(height: 10), - Row( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, + Wrap( children: const [ KeyIndicator.fromIcon(keyIcon: Icons.keyboard_arrow_down), spacing, @@ -86,9 +79,7 @@ class _FlipperControls extends StatelessWidget { const SizedBox(height: 10), Column( children: [ - Row( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, + Wrap( children: const [ KeyIndicator.fromIcon(keyIcon: Icons.keyboard_arrow_left), rowSpacing, @@ -96,9 +87,7 @@ class _FlipperControls extends StatelessWidget { ], ), const SizedBox(height: 8), - Row( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, + Wrap( children: const [ KeyIndicator.fromKeyName(keyName: 'A'), rowSpacing, diff --git a/lib/start_game/widgets/start_game_listener.dart b/lib/start_game/widgets/start_game_listener.dart index 466c3c39..6d249c3c 100644 --- a/lib/start_game/widgets/start_game_listener.dart +++ b/lib/start_game/widgets/start_game_listener.dart @@ -28,7 +28,7 @@ class StartGameListener extends StatelessWidget { _onSelectCharacter(context); break; case StartGameStatus.howToPlay: - _handleHowToPlay(context); + _onHowToPlay(context); break; case StartGameStatus.play: _game.gameFlowController.start(); @@ -41,43 +41,48 @@ class StartGameListener extends StatelessWidget { ); } - void _onSelectCharacter( - BuildContext context, - ) { - showDialog( + void _onSelectCharacter(BuildContext context) { + _showPinballDialog( context: context, - builder: (_) { - // TODO(arturplaczek): remove that when PR with PinballLayout will be - // merged - final height = MediaQuery.of(context).size.height * 0.5; - - return Center( - child: SizedBox( - height: height, - width: height * 1.2, - child: const CharacterSelectionDialog(), - ), - ); - }, + child: const CharacterSelectionDialog(), barrierDismissible: false, ); } } -Future _handleHowToPlay( - BuildContext context, -) async { - final startGameBloc = context.read(); +Future _onHowToPlay(BuildContext context) async { + _showPinballDialog( + context: context, + child: HowToPlayDialog( + onDismissCallback: () { + // We need to add a delay between closing the dialog and starting the + // game. + Future.delayed( + kThemeAnimationDuration, + () => context.read().add(const HowToPlayFinished()), + ); + }, + ), + ); +} + +void _showPinballDialog({ + required BuildContext context, + required Widget child, + bool barrierDismissible = true, +}) { + final gameWidgetWidth = MediaQuery.of(context).size.height * 9 / 16; - await showDialog( + showDialog( context: context, barrierColor: AppColors.transparent, + barrierDismissible: barrierDismissible, builder: (_) { return Center( - child: HowToPlayDialog( - onDismissCallback: () { - startGameBloc.add(const HowToPlayFinished()); - }, + child: SizedBox( + height: gameWidgetWidth, + width: gameWidgetWidth, + child: child, ), ); }, diff --git a/test/game/view/pinball_game_page_test.dart b/test/game/view/pinball_game_page_test.dart index f8b62d05..1795b88e 100644 --- a/test/game/view/pinball_game_page_test.dart +++ b/test/game/view/pinball_game_page_test.dart @@ -198,12 +198,11 @@ void main() { find.byWidgetPredicate((w) => w is GameWidget), findsOneWidget, ); - // TODO(arturplaczek): add Visibility to GameHud based on StartGameBloc - // status - // expect( - // find.byType(GameHud), - // findsNothing, - // ); + + expect( + find.byType(GameHud), + findsNothing, + ); }); testWidgets('renders a hud on play state', (tester) async { diff --git a/test/start_game/widgets/start_game_listener_test.dart b/test/start_game/widgets/start_game_listener_test.dart index e35cef78..5ce4ca94 100644 --- a/test/start_game/widgets/start_game_listener_test.dart +++ b/test/start_game/widgets/start_game_listener_test.dart @@ -137,7 +137,7 @@ void main() { ); testWidgets( - 'calls HowToPlayFinished event after HowToPlayDialog is closed', + 'adds HowToPlayFinished event after closing HowToPlayDialog', (tester) async { whenListen( startGameBloc, From 1bdc0475b71282dd168b6a1ff2c4aa7a3f1cb95e Mon Sep 17 00:00:00 2001 From: arturplaczek Date: Thu, 28 Apr 2022 18:05:36 +0200 Subject: [PATCH 9/9] fix: apply code review --- lib/start_game/widgets/start_game_listener.dart | 4 ++-- test/game/view/widgets/play_button_overlay_test.dart | 2 +- test/select_character/view/character_selection_page_test.dart | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/start_game/widgets/start_game_listener.dart b/lib/start_game/widgets/start_game_listener.dart index 6d249c3c..2afe1a40 100644 --- a/lib/start_game/widgets/start_game_listener.dart +++ b/lib/start_game/widgets/start_game_listener.dart @@ -24,6 +24,8 @@ class StartGameListener extends StatelessWidget { return BlocListener( listener: (context, state) { switch (state.status) { + case StartGameStatus.initial: + break; case StartGameStatus.selectCharacter: _onSelectCharacter(context); break; @@ -33,8 +35,6 @@ class StartGameListener extends StatelessWidget { case StartGameStatus.play: _game.gameFlowController.start(); break; - case StartGameStatus.initial: - break; } }, child: _child, diff --git a/test/game/view/widgets/play_button_overlay_test.dart b/test/game/view/widgets/play_button_overlay_test.dart index 10277dee..a4d53617 100644 --- a/test/game/view/widgets/play_button_overlay_test.dart +++ b/test/game/view/widgets/play_button_overlay_test.dart @@ -26,7 +26,7 @@ void main() { expect(find.text('Play'), findsOneWidget); }); - testWidgets('calls PlayTapped event to StartGameBloc when taped on play', + testWidgets('adds PlayTapped event to StartGameBloc when taped', (tester) async { await tester.pumpApp( const PlayButtonOverlay(), diff --git a/test/select_character/view/character_selection_page_test.dart b/test/select_character/view/character_selection_page_test.dart index 2debdb3f..5cd22f54 100644 --- a/test/select_character/view/character_selection_page_test.dart +++ b/test/select_character/view/character_selection_page_test.dart @@ -87,7 +87,7 @@ void main() { .called(1); }); - testWidgets('calls CharacterSelected event when start is tapped', + testWidgets('adds CharacterSelected event when start is tapped', (tester) async { whenListen( startGameBloc,