From a3dc9d09cff15dfb97409f099981eca355585c5d Mon Sep 17 00:00:00 2001 From: Erick Zanardo Date: Tue, 8 Mar 2022 18:45:51 -0300 Subject: [PATCH 1/5] feat: adding game hud --- lib/game/view/game_hud.dart | 40 ++++++++++++++++++++++ lib/game/view/pinball_game_page.dart | 13 ++++++- lib/game/view/view.dart | 1 + test/game/view/game_hud_test.dart | 32 +++++++++++++++++ test/game/view/pinball_game_page_test.dart | 6 +++- 5 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 lib/game/view/game_hud.dart create mode 100644 test/game/view/game_hud_test.dart diff --git a/lib/game/view/game_hud.dart b/lib/game/view/game_hud.dart new file mode 100644 index 00000000..b694e812 --- /dev/null +++ b/lib/game/view/game_hud.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:pinball/game/game.dart'; + +class GameHud extends StatelessWidget { + const GameHud({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final state = context.watch().state; + + return Container( + color: Colors.redAccent, + width: 200, + height: 100, + padding: const EdgeInsets.all(16), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + '${state.score}', + style: Theme.of(context).textTheme.headline3, + ), + Column( + children: [ + for (var i = 0; i < state.balls; i++) + const Padding( + padding: EdgeInsets.only(top: 6), + child: CircleAvatar( + radius: 8, + backgroundColor: Colors.black, + ), + ), + ], + ), + ], + ), + ); + } +} diff --git a/lib/game/view/pinball_game_page.dart b/lib/game/view/pinball_game_page.dart index 02f5b34c..8a9a981c 100644 --- a/lib/game/view/pinball_game_page.dart +++ b/lib/game/view/pinball_game_page.dart @@ -56,7 +56,18 @@ class _PinballGameViewState extends State { ); } }, - child: GameWidget(game: _game), + child: Stack( + children: [ + Positioned.fill( + child: GameWidget(game: _game), + ), + const Positioned( + top: 8, + left: 8, + child: GameHud(), + ), + ], + ), ); } } diff --git a/lib/game/view/view.dart b/lib/game/view/view.dart index 53d3813a..26b700d3 100644 --- a/lib/game/view/view.dart +++ b/lib/game/view/view.dart @@ -1,2 +1,3 @@ +export 'game_hud.dart'; export 'pinball_game_page.dart'; export 'widgets/widgets.dart'; diff --git a/test/game/view/game_hud_test.dart b/test/game/view/game_hud_test.dart new file mode 100644 index 00000000..40079a2f --- /dev/null +++ b/test/game/view/game_hud_test.dart @@ -0,0 +1,32 @@ +// ignore_for_file: prefer_const_constructors + +import 'package:bloc_test/bloc_test.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:pinball/game/game.dart'; +import '../../helpers/helpers.dart'; + +void main() { + group('GameHud', () { + testWidgets( + 'renders the current score and balls', + (tester) async { + final state = GameState(score: 10, balls: 2); + final gameBloc = MockGameBloc(); + whenListen( + gameBloc, + Stream.value(state), + initialState: state, + ); + + await tester.pumpApp( + GameHud(), + gameBloc: gameBloc, + ); + + expect(find.text('10'), findsOneWidget); + expect(find.byType(CircleAvatar), findsNWidgets(2)); + }, + ); + }); +} diff --git a/test/game/view/pinball_game_page_test.dart b/test/game/view/pinball_game_page_test.dart index d578a1db..746dc2c7 100644 --- a/test/game/view/pinball_game_page_test.dart +++ b/test/game/view/pinball_game_page_test.dart @@ -48,7 +48,7 @@ void main() { }); group('PinballGameView', () { - testWidgets('renders game', (tester) async { + testWidgets('renders game and a hud', (tester) async { final gameBloc = MockGameBloc(); whenListen( gameBloc, @@ -61,6 +61,10 @@ void main() { find.byWidgetPredicate((w) => w is GameWidget), findsOneWidget, ); + expect( + find.byType(GameHud), + findsOneWidget, + ); }); testWidgets( From f9f109ba5aeadfd8618439187b8ea3bad8a88b5f Mon Sep 17 00:00:00 2001 From: Erick Date: Wed, 9 Mar 2022 10:02:50 -0300 Subject: [PATCH 2/5] Apply suggestions from code review Co-authored-by: Alejandro Santiago --- lib/game/view/game_hud.dart | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/game/view/game_hud.dart b/lib/game/view/game_hud.dart index b694e812..beff3391 100644 --- a/lib/game/view/game_hud.dart +++ b/lib/game/view/game_hud.dart @@ -2,7 +2,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:pinball/game/game.dart'; +/// {@template game_hud} +/// Overlay of a [PinballGame] that displays the current [GameState.score] and +/// [GameState.balls]. +/// {@endtemplate} class GameHud extends StatelessWidget { + /// {@macro game_hud} const GameHud({Key? key}) : super(key: key); @override From 38b8a28ffc661563374f37f64e6dc0012475304f Mon Sep 17 00:00:00 2001 From: Erick Zanardo Date: Wed, 9 Mar 2022 10:18:54 -0300 Subject: [PATCH 3/5] feat: pr suggestions --- lib/game/view/game_hud.dart | 5 ++- test/game/view/game_hud_test.dart | 75 +++++++++++++++++++++++++------ 2 files changed, 64 insertions(+), 16 deletions(-) diff --git a/lib/game/view/game_hud.dart b/lib/game/view/game_hud.dart index beff3391..7bf1e8c3 100644 --- a/lib/game/view/game_hud.dart +++ b/lib/game/view/game_hud.dart @@ -26,11 +26,12 @@ class GameHud extends StatelessWidget { '${state.score}', style: Theme.of(context).textTheme.headline3, ), - Column( + Wrap( + direction: Axis.vertical, children: [ for (var i = 0; i < state.balls; i++) const Padding( - padding: EdgeInsets.only(top: 6), + padding: EdgeInsets.only(top: 6, right: 6), child: CircleAvatar( radius: 8, backgroundColor: Colors.black, diff --git a/test/game/view/game_hud_test.dart b/test/game/view/game_hud_test.dart index 40079a2f..27a423ed 100644 --- a/test/game/view/game_hud_test.dart +++ b/test/game/view/game_hud_test.dart @@ -8,25 +8,72 @@ import '../../helpers/helpers.dart'; void main() { group('GameHud', () { + late GameBloc gameBloc; + const initialState = GameState(score: 10, balls: 2); + + void _mockState(GameState state) { + whenListen( + gameBloc, + Stream.value(state), + initialState: state, + ); + } + + Future _pumpHud(WidgetTester tester) async { + await tester.pumpApp( + GameHud(), + gameBloc: gameBloc, + ); + } + + setUp(() { + gameBloc = MockGameBloc(); + _mockState(initialState); + }); + testWidgets( - 'renders the current score and balls', + 'renders the current score', (tester) async { - final state = GameState(score: 10, balls: 2); - final gameBloc = MockGameBloc(); - whenListen( - gameBloc, - Stream.value(state), - initialState: state, - ); + await _pumpHud(tester); + expect(find.text(initialState.score.toString()), findsOneWidget); + }, + ); - await tester.pumpApp( - GameHud(), - gameBloc: gameBloc, + testWidgets( + 'renders the current ball number', + (tester) async { + await _pumpHud(tester); + expect( + find.byType(CircleAvatar), + findsNWidgets(initialState.balls), ); - - expect(find.text('10'), findsOneWidget); - expect(find.byType(CircleAvatar), findsNWidgets(2)); }, ); + + testWidgets('updates the score', (tester) async { + await _pumpHud(tester); + expect(find.text(initialState.score.toString()), findsOneWidget); + + _mockState(initialState.copyWith(score: 20)); + + await tester.pump(); + expect(find.text('20'), findsOneWidget); + }); + + testWidgets('updates the ball number', (tester) async { + await _pumpHud(tester); + expect( + find.byType(CircleAvatar), + findsNWidgets(initialState.balls), + ); + + _mockState(initialState.copyWith(balls: 1)); + + await tester.pump(); + expect( + find.byType(CircleAvatar), + findsNWidgets(1), + ); + }); }); } From 884d8b36b07974dff833f37cc669721d58a26671 Mon Sep 17 00:00:00 2001 From: Erick Zanardo Date: Wed, 9 Mar 2022 10:22:17 -0300 Subject: [PATCH 4/5] fix: lint --- lib/game/view/game_hud.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/game/view/game_hud.dart b/lib/game/view/game_hud.dart index 7bf1e8c3..00eedd2b 100644 --- a/lib/game/view/game_hud.dart +++ b/lib/game/view/game_hud.dart @@ -3,7 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:pinball/game/game.dart'; /// {@template game_hud} -/// Overlay of a [PinballGame] that displays the current [GameState.score] and +/// Overlay of a [PinballGame] that displays the current [GameState.score] and /// [GameState.balls]. /// {@endtemplate} class GameHud extends StatelessWidget { From 84282fe83a67e95eaf5a3b3cb4a66d14192bc7c1 Mon Sep 17 00:00:00 2001 From: Erick Zanardo Date: Wed, 9 Mar 2022 10:51:25 -0300 Subject: [PATCH 5/5] fix: test from rebase --- test/game/view/game_hud_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/game/view/game_hud_test.dart b/test/game/view/game_hud_test.dart index 27a423ed..e7334e41 100644 --- a/test/game/view/game_hud_test.dart +++ b/test/game/view/game_hud_test.dart @@ -9,7 +9,7 @@ import '../../helpers/helpers.dart'; void main() { group('GameHud', () { late GameBloc gameBloc; - const initialState = GameState(score: 10, balls: 2); + const initialState = GameState(score: 10, balls: 2, bonusLetters: []); void _mockState(GameState state) { whenListen(