feat: create score widgets

pull/206/head
arturplaczek 3 years ago
parent b6cd9663b9
commit 19bfd035cc

@ -0,0 +1,59 @@
// 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/l10n/l10n.dart';
import 'package:pinball/theme/theme.dart';
class ScoreBalls extends StatelessWidget {
const ScoreBalls({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
final balls = context.select((GameBloc bloc) => bloc.state.balls);
return Row(
children: [
Text(
l10n.ballCt,
style: AppTextStyle.subtitle1.copyWith(
color: AppColors.orange,
),
),
const SizedBox(width: 8),
Row(
children: [
ScoreBall(isActive: balls >= 1),
ScoreBall(isActive: balls >= 2),
ScoreBall(isActive: balls >= 3),
],
),
],
);
}
}
@visibleForTesting
class ScoreBall extends StatelessWidget {
const ScoreBall({
Key? key,
required this.isActive,
}) : super(key: key);
final bool isActive;
@override
Widget build(BuildContext context) {
final color = isActive ? AppColors.orange : AppColors.orange.withAlpha(128);
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Container(
color: color,
height: 8,
width: 8,
),
);
}
}

@ -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:intl/intl.dart';
import 'package:pinball/game/game.dart';
import 'package:pinball/l10n/l10n.dart';
import 'package:pinball/theme/theme.dart';
class ScoreView extends StatelessWidget {
const ScoreView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final isGameOver = context.select((GameBloc bloc) => bloc.state.isGameOver);
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 8,
),
child: AnimatedSwitcher(
duration: kThemeAnimationDuration,
child: isGameOver ? const _GameOver() : const _ScoreWidget(),
),
);
}
}
class _GameOver extends StatelessWidget {
const _GameOver({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
return Text(
l10n.gameOver,
style: AppTextStyle.headline1.copyWith(
color: AppColors.white,
),
);
}
}
class _ScoreWidget extends StatelessWidget {
const _ScoreWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
l10n.score.toLowerCase(),
style: AppTextStyle.subtitle1.copyWith(
color: AppColors.orange,
),
),
const _ScoreText(),
const ScoreBalls(),
],
);
}
}
class _ScoreText extends StatelessWidget {
const _ScoreText({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final score = context.select((GameBloc bloc) => bloc.state.score);
final numberFormatter = NumberFormat.decimalPattern('en_US');
final formattedScore = numberFormatter.format(score).replaceAll(',', '.');
return Text(
formattedScore,
style: AppTextStyle.headline1.copyWith(
color: AppColors.white,
),
);
}
}

@ -1,3 +1,5 @@
export 'bonus_animation.dart';
export 'game_hud.dart';
export 'play_button_overlay.dart';
export 'score_ball.dart';
export 'score_view.dart';

@ -0,0 +1,101 @@
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 'package:pinball/theme/app_colors.dart';
import '../../../helpers/helpers.dart';
void main() {
group('ScoreBalls renders', () {
late GameBloc gameBloc;
const initialState = GameState(
score: 0,
balls: 3,
bonusHistory: [],
);
setUp(() {
gameBloc = MockGameBloc();
whenListen(
gameBloc,
Stream.value(initialState),
initialState: initialState,
);
});
testWidgets('three active balls', (tester) async {
await tester.pumpApp(
const ScoreBalls(),
gameBloc: gameBloc,
);
await tester.pump();
expect(find.byType(ScoreBall), findsNWidgets(3));
});
testWidgets('two active balls', (tester) async {
final state = initialState.copyWith(
balls: 2,
);
whenListen(
gameBloc,
Stream.value(state),
initialState: state,
);
await tester.pumpApp(
const ScoreBalls(),
gameBloc: gameBloc,
);
await tester.pump();
expect(
find.byWidgetPredicate(
(widget) => widget is ScoreBall && widget.isActive,
),
findsNWidgets(2),
);
expect(
find.byWidgetPredicate(
(widget) => widget is ScoreBall && !widget.isActive,
),
findsOneWidget,
);
});
});
testWidgets('active score ball is displaying with proper color',
(tester) async {
await tester.pumpApp(
const ScoreBall(isActive: true),
);
await tester.pump();
expect(
find.byWidgetPredicate(
(widget) => widget is Container && widget.color == AppColors.orange,
),
findsOneWidget,
);
});
testWidgets('inactive score ball is displaying with proper color',
(tester) async {
await tester.pumpApp(
const ScoreBall(isActive: false),
);
await tester.pump();
expect(
find.byWidgetPredicate(
(widget) =>
widget is Container &&
widget.color == AppColors.orange.withAlpha(128),
),
findsOneWidget,
);
});
}

@ -0,0 +1,86 @@
import 'dart:async';
import 'package:bloc_test/bloc_test.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:intl/intl.dart';
import 'package:pinball/game/game.dart';
import 'package:pinball/l10n/l10n.dart';
import '../../../helpers/helpers.dart';
void main() {
late GameBloc gameBloc;
late StreamController<GameState> stateController;
const score = 123456789;
const initialState = GameState(
score: score,
balls: 1,
bonusHistory: [],
);
setUp(() {
gameBloc = MockGameBloc();
stateController = StreamController<GameState>()..add(initialState);
whenListen(
gameBloc,
stateController.stream,
initialState: initialState,
);
});
String _formatScore(int score) {
final numberFormatter = NumberFormat.decimalPattern('en_US');
return numberFormatter.format(score).replaceAll(',', '.');
}
group('ScoreView', () {
testWidgets('renders score', (tester) async {
await tester.pumpApp(
const ScoreView(),
gameBloc: gameBloc,
);
await tester.pump();
expect(find.text(_formatScore(score)), findsOneWidget);
});
testWidgets('renders game over', (tester) async {
final l10n = await AppLocalizations.delegate.load(const Locale('en'));
stateController.add(
initialState.copyWith(
balls: 0,
),
);
await tester.pumpApp(
const ScoreView(),
gameBloc: gameBloc,
);
await tester.pump();
expect(find.text(l10n.gameOver), findsOneWidget);
});
testWidgets('updates the score', (tester) async {
await tester.pumpApp(
const ScoreView(),
gameBloc: gameBloc,
);
expect(find.text('$score'), findsOneWidget);
final newState = initialState.copyWith(
score: 987654321,
);
stateController.add(newState);
await tester.pump();
expect(find.text(_formatScore(newState.score)), findsOneWidget);
});
});
}
Loading…
Cancel
Save