feat: final screen for the initials submission error (#393)

pull/401/head
Erick 2 years ago committed by GitHub
parent 75feeaae26
commit 6aef28ed8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -89,7 +89,18 @@ class Backbox extends PositionComponent with ZIndex, HasGameRef {
} else if (state is InitialsSuccessState) {
_display.add(InitialsSubmissionSuccessDisplay());
} else if (state is InitialsFailureState) {
_display.add(InitialsSubmissionFailureDisplay());
_display.add(
InitialsSubmissionFailureDisplay(
onDismissed: () {
_bloc.add(
PlayerInitialsRequested(
score: state.score,
character: state.character,
),
);
},
),
);
}
}

@ -56,7 +56,12 @@ class BackboxBloc extends Bloc<BackboxEvent, BackboxState> {
emit(InitialsSuccessState());
} catch (error, stackTrace) {
addError(error, stackTrace);
emit(InitialsFailureState());
emit(
InitialsFailureState(
score: event.score,
character: event.character,
),
);
}
}

@ -62,6 +62,17 @@ class InitialsSuccessState extends BackboxState {
/// State when the initials submission failed.
class InitialsFailureState extends BackboxState {
const InitialsFailureState({
required this.score,
required this.character,
});
/// Player's score.
final int score;
/// Player's character.
final CharacterTheme character;
@override
List<Object?> get props => [];
List<Object?> get props => [score, character];
}

@ -1,27 +1,47 @@
import 'package:flame/components.dart';
import 'package:flutter/material.dart';
import 'package:pinball/game/game.dart';
import 'package:pinball/l10n/l10n.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
import 'package:pinball_ui/pinball_ui.dart';
final _bodyTextPaint = TextPaint(
style: const TextStyle(
fontSize: 3,
fontSize: 1.8,
color: PinballColors.white,
fontFamily: PinballFonts.pixeloidSans,
fontWeight: FontWeight.w400,
),
);
/// {@template initials_submission_failure_display}
/// [Backbox] display for when a failure occurs during initials submission.
/// {@endtemplate}
class InitialsSubmissionFailureDisplay extends TextComponent {
class InitialsSubmissionFailureDisplay extends Component {
/// {@macro initials_submission_failure_display}
InitialsSubmissionFailureDisplay({
required this.onDismissed,
});
final VoidCallback onDismissed;
@override
Future<void> onLoad() async {
await super.onLoad();
position = Vector2(0, -10);
anchor = Anchor.center;
text = 'Failure!';
textRenderer = _bodyTextPaint;
final l10n = readProvider<AppLocalizations>();
await addAll([
ErrorComponent.bold(
label: l10n.initialsErrorTitle,
position: Vector2(0, -20),
),
TextComponent(
text: l10n.initialsErrorMessage,
anchor: Anchor.center,
position: Vector2(0, -12),
textRenderer: _bodyTextPaint,
),
TimerComponent(period: 4, onTick: onDismissed),
]);
}
}

@ -152,6 +152,14 @@
"@enter": {
"description": "Text shown on the mobile controls enter button"
},
"initialsErrorTitle": "Uh-oh... well, that didnt work",
"@enter": {
"description": "Title shown when the initials submission fails"
},
"initialsErrorMessage": "Please try a different combination of letters",
"@initialsErrorMessage": {
"description": "Message on shown when the initials submission fails"
},
"leaderboardErrorMessage": "No connection. Leaderboard and sharing functionality is unavailable.",
"@leaderboardErrorMessage": {
"description": "Text shown when the leaderboard had an error while loading"

@ -100,6 +100,12 @@ class _MockAppLocalizations extends Mock implements AppLocalizations {
@override
String get loading => '';
@override
String get initialsErrorTitle => '';
@override
String get initialsErrorMessage => '';
@override
String get leaderboardErrorMessage => '';
}
@ -273,7 +279,10 @@ void main() {
whenListen(
bloc,
Stream<BackboxState>.empty(),
initialState: InitialsFailureState(),
initialState: InitialsFailureState(
score: 0,
character: theme.DashTheme(),
),
);
final backbox = Backbox.test(
bloc: bloc,
@ -354,7 +363,12 @@ void main() {
backbox.removeFromParent();
await game.ready();
streamController.add(InitialsFailureState());
streamController.add(
InitialsFailureState(
score: 10,
character: theme.DashTheme(),
),
);
await game.ready();
expect(
@ -366,5 +380,36 @@ void main() {
);
},
);
flameTester.test(
'adds PlayerInitialsSubmitted when the timer is finished',
(game) async {
final initialState = InitialsFailureState(
score: 10,
character: theme.DashTheme(),
);
whenListen(
bloc,
Stream<BackboxState>.fromIterable([]),
initialState: initialState,
);
final backbox = Backbox.test(
bloc: bloc,
platformHelper: platformHelper,
);
await game.pump(backbox);
game.update(4);
verify(
() => bloc.add(
PlayerInitialsRequested(
score: 10,
character: theme.DashTheme(),
),
),
).called(1);
},
);
});
}

@ -113,7 +113,7 @@ void main() {
),
expect: () => [
LoadingState(),
InitialsFailureState(),
InitialsFailureState(score: 10, character: DashTheme()),
],
);
});

@ -124,11 +124,56 @@ void main() {
group('InitialsFailureState', () {
test('can be instantiated', () {
expect(InitialsFailureState(), isNotNull);
expect(
InitialsFailureState(
score: 10,
character: AndroidTheme(),
),
isNotNull,
);
});
test('supports value comparison', () {
expect(InitialsFailureState(), equals(InitialsFailureState()));
expect(
InitialsFailureState(
score: 10,
character: AndroidTheme(),
),
equals(
InitialsFailureState(
score: 10,
character: AndroidTheme(),
),
),
);
expect(
InitialsFailureState(
score: 10,
character: AndroidTheme(),
),
isNot(
equals(
InitialsFailureState(
score: 12,
character: AndroidTheme(),
),
),
),
);
expect(
InitialsFailureState(
score: 10,
character: AndroidTheme(),
),
isNot(
equals(
InitialsFailureState(
score: 10,
character: DashTheme(),
),
),
),
);
});
});
});

@ -4,18 +4,74 @@ import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:pinball/game/components/backbox/displays/initials_submission_failure_display.dart';
import 'package:pinball/l10n/l10n.dart';
import 'package:pinball_components/gen/assets.gen.dart';
import 'package:pinball_flame/pinball_flame.dart';
class _TestGame extends Forge2DGame {
@override
Future<void> onLoad() async {
await super.onLoad();
images.prefix = '';
await images.loadAll(
[
Assets.images.errorBackground.keyName,
],
);
}
Future<void> pump(InitialsSubmissionFailureDisplay component) {
return ensureAdd(
FlameProvider.value(
_MockAppLocalizations(),
children: [component],
),
);
}
}
class _MockAppLocalizations extends Mock implements AppLocalizations {
@override
String get initialsErrorTitle => 'Title';
@override
String get initialsErrorMessage => 'Message';
}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('InitialsSubmissionFailureDisplay', () {
final flameTester = FlameTester(Forge2DGame.new);
final flameTester = FlameTester(_TestGame.new);
flameTester.test('renders correctly', (game) async {
await game.ensureAdd(InitialsSubmissionFailureDisplay());
await game.pump(
InitialsSubmissionFailureDisplay(
onDismissed: () {},
),
);
final component = game.firstChild<TextComponent>();
expect(component, isNotNull);
expect(component?.text, equals('Failure!'));
expect(
game
.descendants()
.where(
(component) =>
component is TextComponent && component.text == 'Title',
)
.length,
equals(1),
);
expect(
game
.descendants()
.where(
(component) =>
component is TextComponent && component.text == 'Message',
)
.length,
equals(1),
);
});
});
}

Loading…
Cancel
Save