Merge branch 'main' into feat/add-cspell

pull/399/head
Tom Arra 3 years ago committed by GitHub
commit 95cf07f5b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -65,6 +65,8 @@ class Backbox extends PositionComponent with ZIndex, HasGameRef {
_display.add(LoadingDisplay()); _display.add(LoadingDisplay());
} else if (state is LeaderboardSuccessState) { } else if (state is LeaderboardSuccessState) {
_display.add(LeaderboardDisplay(entries: state.entries)); _display.add(LeaderboardDisplay(entries: state.entries));
} else if (state is LeaderboardFailureState) {
_display.add(LeaderboardFailureDisplay());
} else if (state is InitialsFormState) { } else if (state is InitialsFormState) {
if (_platformHelper.isMobile) { if (_platformHelper.isMobile) {
gameRef.overlays.add(PinballGame.mobileControlsOverlay); gameRef.overlays.add(PinballGame.mobileControlsOverlay);
@ -87,7 +89,18 @@ class Backbox extends PositionComponent with ZIndex, HasGameRef {
} else if (state is InitialsSuccessState) { } else if (state is InitialsSuccessState) {
_display.add(InitialsSubmissionSuccessDisplay()); _display.add(InitialsSubmissionSuccessDisplay());
} else if (state is InitialsFailureState) { } 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()); emit(InitialsSuccessState());
} catch (error, stackTrace) { } catch (error, stackTrace) {
addError(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. /// State when the initials submission failed.
class InitialsFailureState extends BackboxState { 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 @override
List<Object?> get props => []; List<Object?> get props => [score, character];
} }

@ -2,4 +2,5 @@ export 'initials_input_display.dart';
export 'initials_submission_failure_display.dart'; export 'initials_submission_failure_display.dart';
export 'initials_submission_success_display.dart'; export 'initials_submission_success_display.dart';
export 'leaderboard_display.dart'; export 'leaderboard_display.dart';
export 'leaderboard_failure_display.dart';
export 'loading_display.dart'; export 'loading_display.dart';

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

@ -0,0 +1,23 @@
import 'package:flame/components.dart';
import 'package:pinball/l10n/l10n.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
/// {@template leaderboard_failure_display}
/// Display showing an error message when the leaderboard couldn't be loaded
/// {@endtemplate}
class LeaderboardFailureDisplay extends Component {
/// {@macro leaderboard_failure_display}
LeaderboardFailureDisplay();
@override
Future<void> onLoad() async {
final l10n = readProvider<AppLocalizations>();
await add(
ErrorComponent(
label: l10n.leaderboardErrorMessage,
position: Vector2(0, -18),
),
);
}
}

@ -151,5 +151,17 @@
"enter": "Enter", "enter": "Enter",
"@enter": { "@enter": {
"description": "Text shown on the mobile controls enter button" "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"
} }
} }

@ -99,6 +99,15 @@ class _MockAppLocalizations extends Mock implements AppLocalizations {
@override @override
String get loading => ''; String get loading => '';
@override
String get initialsErrorTitle => '';
@override
String get initialsErrorMessage => '';
@override
String get leaderboardErrorMessage => '';
} }
void main() { void main() {
@ -270,7 +279,10 @@ void main() {
whenListen( whenListen(
bloc, bloc,
Stream<BackboxState>.empty(), Stream<BackboxState>.empty(),
initialState: InitialsFailureState(), initialState: InitialsFailureState(
score: 0,
character: theme.DashTheme(),
),
); );
final backbox = Backbox.test( final backbox = Backbox.test(
bloc: bloc, bloc: bloc,
@ -310,6 +322,28 @@ void main() {
}, },
); );
flameTester.test(
'adds LeaderboardFailureDisplay on LeaderboardFailureState',
(game) async {
whenListen(
bloc,
Stream<BackboxState>.empty(),
initialState: LeaderboardFailureState(),
);
final backbox = Backbox.test(
bloc: bloc,
platformHelper: platformHelper,
);
await game.pump(backbox);
expect(
game.descendants().whereType<LeaderboardFailureDisplay>().length,
equals(1),
);
},
);
flameTester.test( flameTester.test(
'closes the subscription when it is removed', 'closes the subscription when it is removed',
(game) async { (game) async {
@ -329,7 +363,12 @@ void main() {
backbox.removeFromParent(); backbox.removeFromParent();
await game.ready(); await game.ready();
streamController.add(InitialsFailureState()); streamController.add(
InitialsFailureState(
score: 10,
character: theme.DashTheme(),
),
);
await game.ready(); await game.ready();
expect( expect(
@ -341,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: () => [ expect: () => [
LoadingState(), LoadingState(),
InitialsFailureState(), InitialsFailureState(score: 10, character: DashTheme()),
], ],
); );
}); });

@ -124,11 +124,56 @@ void main() {
group('InitialsFailureState', () { group('InitialsFailureState', () {
test('can be instantiated', () { test('can be instantiated', () {
expect(InitialsFailureState(), isNotNull); expect(
InitialsFailureState(
score: 10,
character: AndroidTheme(),
),
isNotNull,
);
}); });
test('supports value comparison', () { 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_forge2d/flame_forge2d.dart';
import 'package:flame_test/flame_test.dart'; import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_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/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() { void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('InitialsSubmissionFailureDisplay', () { group('InitialsSubmissionFailureDisplay', () {
final flameTester = FlameTester(Forge2DGame.new); final flameTester = FlameTester(_TestGame.new);
flameTester.test('renders correctly', (game) async { flameTester.test('renders correctly', (game) async {
await game.ensureAdd(InitialsSubmissionFailureDisplay()); await game.pump(
InitialsSubmissionFailureDisplay(
onDismissed: () {},
),
);
final component = game.firstChild<TextComponent>(); expect(
expect(component, isNotNull); game
expect(component?.text, equals('Failure!')); .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),
);
}); });
}); });
} }

@ -0,0 +1,60 @@
// ignore_for_file: cascade_invocations
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/displays.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(LeaderboardFailureDisplay component) {
return ensureAdd(
FlameProvider.value(
_MockAppLocalizations(),
children: [component],
),
);
}
}
class _MockAppLocalizations extends Mock implements AppLocalizations {
@override
String get leaderboardErrorMessage => 'Message';
}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('LeaderboardFailureDisplay', () {
final flameTester = FlameTester(_TestGame.new);
flameTester.test('renders correctly', (game) async {
await game.pump(LeaderboardFailureDisplay());
expect(
game
.descendants()
.where(
(component) =>
component is TextComponent && component.text == 'Message',
)
.length,
equals(1),
);
});
});
}

@ -57,7 +57,10 @@ class _TestDebugPinballGame extends DebugPinballGame {
class _MockGameBloc extends Mock implements GameBloc {} class _MockGameBloc extends Mock implements GameBloc {}
class _MockAppLocalizations extends Mock implements AppLocalizations {} class _MockAppLocalizations extends Mock implements AppLocalizations {
@override
String get leaderboardErrorMessage => '';
}
class _MockEventPosition extends Mock implements EventPosition {} class _MockEventPosition extends Mock implements EventPosition {}

@ -50,7 +50,10 @@ class _MockAssetsManagerCubit extends Mock implements AssetsManagerCubit {}
class _MockStartGameBloc extends Mock implements StartGameBloc {} class _MockStartGameBloc extends Mock implements StartGameBloc {}
class _MockAppLocalizations extends Mock implements AppLocalizations {} class _MockAppLocalizations extends Mock implements AppLocalizations {
@override
String get leaderboardErrorMessage => '';
}
class _MockPinballAudioPlayer extends Mock implements PinballAudioPlayer {} class _MockPinballAudioPlayer extends Mock implements PinballAudioPlayer {}

Loading…
Cancel
Save