feat: improving pinball audio code and loading (#325)

* feat: improving pinball audio code and loading

* fix: some errors

* refactoring the solution

* Apply suggestions from code review

Co-authored-by: Alejandro Santiago <dev@alestiago.com>

* fix: tests

* fix rebase

Co-authored-by: Alejandro Santiago <dev@alestiago.com>
Co-authored-by: Tom Arra <tarra3@gmail.com>
pull/320/head
Erick 3 years ago committed by GitHub
parent 9d98ff37fb
commit 34d0e7d65a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -17,15 +17,15 @@ class App extends StatelessWidget {
Key? key,
required AuthenticationRepository authenticationRepository,
required LeaderboardRepository leaderboardRepository,
required PinballAudio pinballAudio,
required PinballPlayer pinballPlayer,
}) : _authenticationRepository = authenticationRepository,
_leaderboardRepository = leaderboardRepository,
_pinballAudio = pinballAudio,
_pinballPlayer = pinballPlayer,
super(key: key);
final AuthenticationRepository _authenticationRepository;
final LeaderboardRepository _leaderboardRepository;
final PinballAudio _pinballAudio;
final PinballPlayer _pinballPlayer;
@override
Widget build(BuildContext context) {
@ -33,7 +33,7 @@ class App extends StatelessWidget {
providers: [
RepositoryProvider.value(value: _authenticationRepository),
RepositoryProvider.value(value: _leaderboardRepository),
RepositoryProvider.value(value: _pinballAudio),
RepositoryProvider.value(value: _pinballPlayer),
],
child: MultiBlocProvider(
providers: [

@ -3,12 +3,13 @@
import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:pinball/game/pinball_game.dart';
import 'package:pinball_audio/pinball_audio.dart';
import 'package:pinball_flame/pinball_flame.dart';
class BumperNoisyBehavior extends ContactBehavior with HasGameRef<PinballGame> {
@override
void beginContact(Object other, Contact contact) {
super.beginContact(other, contact);
gameRef.audio.bumper();
gameRef.player.play(PinballAudio.bumper);
}
}

@ -1,6 +1,7 @@
import 'package:flame/components.dart';
import 'package:flame_bloc/flame_bloc.dart';
import 'package:pinball/game/game.dart';
import 'package:pinball_audio/pinball_audio.dart';
import 'package:pinball_flame/pinball_flame.dart';
/// {@template game_flow_controller}
@ -38,7 +39,7 @@ class GameFlowController extends ComponentController<PinballGame>
/// Puts the game in the playing state.
void start() {
component.audio.backgroundMusic();
component.player.play(PinballAudio.backgroundMusic);
component.firstChild<CameraController>()?.focusOnGame();
component.overlays.remove(PinballGame.playButtonOverlay);
}

@ -1,5 +1,6 @@
import 'package:flame/components.dart';
import 'package:pinball/game/game.dart';
import 'package:pinball_audio/pinball_audio.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
@ -20,7 +21,7 @@ class GoogleWordBonusBehavior extends Component
.every((letter) => letter.bloc.state == GoogleLetterState.lit);
if (achievedBonus) {
gameRef.audio.googleBonus();
gameRef.player.play(PinballAudio.google);
gameRef
.read<GameBloc>()
.add(const BonusActivated(GameBonus.googleWord));

@ -23,8 +23,8 @@ class PinballGame extends PinballForge2DGame
MultiTouchTapDetector {
PinballGame({
required this.characterTheme,
required this.audio,
required this.l10n,
required this.player,
}) : super(gravity: Vector2(0, 30)) {
images.prefix = '';
controller = _GameBallsController(this);
@ -38,7 +38,7 @@ class PinballGame extends PinballForge2DGame
final CharacterTheme characterTheme;
final PinballAudio audio;
final PinballPlayer player;
final AppLocalizations l10n;
@ -186,11 +186,11 @@ class _GameBallsController extends ComponentController<PinballGame>
class DebugPinballGame extends PinballGame with FPSCounter, PanDetector {
DebugPinballGame({
required CharacterTheme characterTheme,
required PinballAudio audio,
required AppLocalizations l10n,
required PinballPlayer player,
}) : super(
characterTheme: characterTheme,
audio: audio,
player: player,
l10n: l10n,
) {
controller = _GameBallsController(this);

@ -36,24 +36,24 @@ class PinballGamePage extends StatelessWidget {
Widget build(BuildContext context) {
final characterTheme =
context.read<CharacterThemeCubit>().state.characterTheme;
final audio = context.read<PinballAudio>();
final pinballAudio = context.read<PinballAudio>();
final player = context.read<PinballPlayer>();
final pinballAudio = context.read<PinballPlayer>();
final game = isDebugMode
? DebugPinballGame(
characterTheme: characterTheme,
audio: audio,
player: player,
l10n: context.l10n,
)
: PinballGame(
characterTheme: characterTheme,
audio: audio,
player: player,
l10n: context.l10n,
);
final loadables = [
...game.preLoadAssets(),
pinballAudio.load(),
...pinballAudio.load(),
...BonusAnimation.loadAssets(),
...SelectedCharacter.loadAssets(),
];

@ -3,8 +3,10 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:pinball/gen/gen.dart';
import 'package:pinball/l10n/l10n.dart';
import 'package:pinball_audio/pinball_audio.dart';
import 'package:pinball_ui/pinball_ui.dart';
import 'package:platform_helper/platform_helper.dart';
@ -91,6 +93,7 @@ class _HowToPlayDialogState extends State<HowToPlayDialog> {
return WillPopScope(
onWillPop: () {
widget.onDismissCallback.call();
context.read<PinballPlayer>().play(PinballAudio.ioPinballVoiceOver);
return Future.value(true);
},
child: PinballDialog(

@ -11,7 +11,7 @@ void main() {
bootstrap((firestore, firebaseAuth) async {
final leaderboardRepository = LeaderboardRepository(firestore);
final authenticationRepository = AuthenticationRepository(firebaseAuth);
final pinballAudio = PinballAudio();
final pinballPlayer = PinballPlayer();
unawaited(
Firebase.initializeApp().then(
(_) => authenticationRepository.authenticateAnonymously(),
@ -20,7 +20,7 @@ void main() {
return App(
authenticationRepository: authenticationRepository,
leaderboardRepository: leaderboardRepository,
pinballAudio: pinballAudio,
pinballPlayer: pinballPlayer,
);
});
}

@ -11,7 +11,7 @@ void main() {
bootstrap((firestore, firebaseAuth) async {
final leaderboardRepository = LeaderboardRepository(firestore);
final authenticationRepository = AuthenticationRepository(firebaseAuth);
final pinballAudio = PinballAudio();
final pinballPlayer = PinballPlayer();
unawaited(
Firebase.initializeApp().then(
(_) => authenticationRepository.authenticateAnonymously(),
@ -20,7 +20,7 @@ void main() {
return App(
authenticationRepository: authenticationRepository,
leaderboardRepository: leaderboardRepository,
pinballAudio: pinballAudio,
pinballPlayer: pinballPlayer,
);
});
}

@ -11,7 +11,7 @@ void main() {
bootstrap((firestore, firebaseAuth) async {
final leaderboardRepository = LeaderboardRepository(firestore);
final authenticationRepository = AuthenticationRepository(firebaseAuth);
final pinballAudio = PinballAudio();
final pinballPlayer = PinballPlayer();
unawaited(
Firebase.initializeApp().then(
(_) => authenticationRepository.authenticateAnonymously(),
@ -20,7 +20,7 @@ void main() {
return App(
authenticationRepository: authenticationRepository,
leaderboardRepository: leaderboardRepository,
pinballAudio: pinballAudio,
pinballPlayer: pinballPlayer,
);
});
}

@ -4,7 +4,6 @@ import 'package:pinball/game/game.dart';
import 'package:pinball/how_to_play/how_to_play.dart';
import 'package:pinball/select_character/select_character.dart';
import 'package:pinball/start_game/start_game.dart';
import 'package:pinball_audio/pinball_audio.dart';
import 'package:pinball_ui/pinball_ui.dart';
/// {@template start_game_listener}
@ -57,14 +56,11 @@ class StartGameListener extends StatelessWidget {
}
void _onHowToPlay(BuildContext context) {
final audio = context.read<PinballAudio>();
_showPinballDialog(
context: context,
child: HowToPlayDialog(
onDismissCallback: () {
context.read<StartGameBloc>().add(const HowToPlayFinished());
audio.ioPinballVoiceOver();
},
),
);

@ -3,10 +3,25 @@ import 'dart:math';
import 'package:audioplayers/audioplayers.dart';
import 'package:flame_audio/audio_pool.dart';
import 'package:flame_audio/flame_audio.dart';
import 'package:flutter/material.dart';
import 'package:pinball_audio/gen/assets.gen.dart';
/// Function that defines the contract of the creation
/// of an [AudioPool]
/// Sounds available for play
enum PinballAudio {
/// Google
google,
/// Bumper
bumper,
/// Background music
backgroundMusic,
/// IO Pinball voice over
ioPinballVoiceOver
}
/// Defines the contract of the creation of an [AudioPool].
typedef CreateAudioPool = Future<AudioPool> Function(
String sound, {
bool? repeating,
@ -31,12 +46,97 @@ typedef PreCacheSingleAudio = Future<void> Function(String);
/// an [AudioCache] instance
typedef ConfigureAudioCache = void Function(AudioCache);
/// {@template pinball_audio}
abstract class _Audio {
void play();
Future<void> load();
String prefixFile(String file) {
return 'packages/pinball_audio/$file';
}
}
class _SimplePlayAudio extends _Audio {
_SimplePlayAudio({
required this.preCacheSingleAudio,
required this.playSingleAudio,
required this.path,
});
final PreCacheSingleAudio preCacheSingleAudio;
final PlaySingleAudio playSingleAudio;
final String path;
@override
Future<void> load() => preCacheSingleAudio(prefixFile(path));
@override
void play() {
playSingleAudio(prefixFile(path));
}
}
class _LoopAudio extends _Audio {
_LoopAudio({
required this.preCacheSingleAudio,
required this.loopSingleAudio,
required this.path,
});
final PreCacheSingleAudio preCacheSingleAudio;
final LoopSingleAudio loopSingleAudio;
final String path;
@override
Future<void> load() => preCacheSingleAudio(prefixFile(path));
@override
void play() {
loopSingleAudio(prefixFile(path));
}
}
class _BumperAudio extends _Audio {
_BumperAudio({
required this.createAudioPool,
required this.seed,
});
final CreateAudioPool createAudioPool;
final Random seed;
late AudioPool bumperA;
late AudioPool bumperB;
@override
Future<void> load() async {
await Future.wait(
[
createAudioPool(
prefixFile(Assets.sfx.bumperA),
maxPlayers: 4,
prefix: '',
).then((pool) => bumperA = pool),
createAudioPool(
prefixFile(Assets.sfx.bumperB),
maxPlayers: 4,
prefix: '',
).then((pool) => bumperB = pool),
],
);
}
@override
void play() {
(seed.nextBool() ? bumperA : bumperB).start(volume: 0.6);
}
}
/// {@template pinball_player}
/// Sound manager for the pinball game
/// {@endtemplate}
class PinballAudio {
/// {@macro pinball_audio}
PinballAudio({
class PinballPlayer {
/// {@macro pinball_player}
PinballPlayer({
CreateAudioPool? createAudioPool,
PlaySingleAudio? playSingleAudio,
LoopSingleAudio? loopSingleAudio,
@ -52,7 +152,29 @@ class PinballAudio {
((AudioCache a) {
a.prefix = '';
}),
_seed = seed ?? Random();
_seed = seed ?? Random() {
audios = {
PinballAudio.google: _SimplePlayAudio(
preCacheSingleAudio: _preCacheSingleAudio,
playSingleAudio: _playSingleAudio,
path: Assets.sfx.google,
),
PinballAudio.ioPinballVoiceOver: _SimplePlayAudio(
preCacheSingleAudio: _preCacheSingleAudio,
playSingleAudio: _playSingleAudio,
path: Assets.sfx.ioPinballVoiceOver,
),
PinballAudio.bumper: _BumperAudio(
createAudioPool: _createAudioPool,
seed: _seed,
),
PinballAudio.backgroundMusic: _LoopAudio(
preCacheSingleAudio: _preCacheSingleAudio,
loopSingleAudio: _loopSingleAudio,
path: Assets.music.background,
),
};
}
final CreateAudioPool _createAudioPool;
@ -66,54 +188,24 @@ class PinballAudio {
final Random _seed;
late AudioPool _bumperAPool;
late AudioPool _bumperBPool;
/// Registered audios on the Player
@visibleForTesting
// ignore: library_private_types_in_public_api
late final Map<PinballAudio, _Audio> audios;
/// Loads the sounds effects into the memory
Future<void> load() async {
List<Future<void>> load() {
_configureAudioCache(FlameAudio.audioCache);
_bumperAPool = await _createAudioPool(
_prefixFile(Assets.sfx.bumperA),
maxPlayers: 4,
prefix: '',
);
_bumperBPool = await _createAudioPool(
_prefixFile(Assets.sfx.bumperB),
maxPlayers: 4,
prefix: '',
);
await Future.wait([
_preCacheSingleAudio(_prefixFile(Assets.sfx.google)),
_preCacheSingleAudio(_prefixFile(Assets.sfx.ioPinballVoiceOver)),
_preCacheSingleAudio(_prefixFile(Assets.music.background)),
]);
}
/// Plays a random bumper sfx.
void bumper() {
(_seed.nextBool() ? _bumperAPool : _bumperBPool).start(volume: 0.6);
return audios.values.map((a) => a.load()).toList();
}
/// Plays the google word bonus
void googleBonus() {
_playSingleAudio(_prefixFile(Assets.sfx.google));
}
/// Plays the I/O Pinball voice over audio.
void ioPinballVoiceOver() {
_playSingleAudio(_prefixFile(Assets.sfx.ioPinballVoiceOver));
}
/// Plays the background music
void backgroundMusic() {
_loopSingleAudio(_prefixFile(Assets.music.background));
}
String _prefixFile(String file) {
return 'packages/pinball_audio/$file';
/// Plays the received auido
void play(PinballAudio audio) {
assert(
audios.containsKey(audio),
'Tried to play unregistered audio $audio',
);
audios[audio]?.play();
}
}

@ -51,7 +51,7 @@ void main() {
late _MockLoopSingleAudio loopSingleAudio;
late _PreCacheSingleAudio preCacheSingleAudio;
late Random seed;
late PinballAudio audio;
late PinballPlayer player;
setUpAll(() {
registerFallbackValue(_MockAudioCache());
@ -81,7 +81,7 @@ void main() {
seed = _MockRandom();
audio = PinballAudio(
player = PinballPlayer(
configureAudioCache: configureAudioCache.onCall,
createAudioPool: createAudioPool.onCall,
playSingleAudio: playSingleAudio.onCall,
@ -92,12 +92,12 @@ void main() {
});
test('can be instantiated', () {
expect(PinballAudio(), isNotNull);
expect(PinballPlayer(), isNotNull);
});
group('load', () {
test('creates the bumpers pools', () async {
await audio.load();
await Future.wait(player.load());
verify(
() => createAudioPool.onCall(
@ -117,25 +117,25 @@ void main() {
});
test('configures the audio cache instance', () async {
await audio.load();
await Future.wait(player.load());
verify(() => configureAudioCache.onCall(FlameAudio.audioCache))
.called(1);
});
test('sets the correct prefix', () async {
audio = PinballAudio(
player = PinballPlayer(
createAudioPool: createAudioPool.onCall,
playSingleAudio: playSingleAudio.onCall,
preCacheSingleAudio: preCacheSingleAudio.onCall,
);
await audio.load();
await Future.wait(player.load());
expect(FlameAudio.audioCache.prefix, equals(''));
});
test('pre cache the assets', () async {
await audio.load();
await Future.wait(player.load());
verify(
() => preCacheSingleAudio
@ -184,8 +184,8 @@ void main() {
group('when seed is true', () {
test('plays the bumper A sound pool', () async {
when(seed.nextBool).thenReturn(true);
await audio.load();
audio.bumper();
await Future.wait(player.load());
player.play(PinballAudio.bumper);
verify(() => bumperAPool.start(volume: 0.6)).called(1);
});
@ -194,8 +194,8 @@ void main() {
group('when seed is false', () {
test('plays the bumper B sound pool', () async {
when(seed.nextBool).thenReturn(false);
await audio.load();
audio.bumper();
await Future.wait(player.load());
player.play(PinballAudio.bumper);
verify(() => bumperBPool.start(volume: 0.6)).called(1);
});
@ -204,8 +204,8 @@ void main() {
group('googleBonus', () {
test('plays the correct file', () async {
await audio.load();
audio.googleBonus();
await Future.wait(player.load());
player.play(PinballAudio.google);
verify(
() => playSingleAudio
@ -216,8 +216,8 @@ void main() {
group('ioPinballVoiceOver', () {
test('plays the correct file', () async {
await audio.load();
audio.ioPinballVoiceOver();
await Future.wait(player.load());
player.play(PinballAudio.ioPinballVoiceOver);
verify(
() => playSingleAudio.onCall(
@ -229,8 +229,8 @@ void main() {
group('backgroundMusic', () {
test('plays the correct file', () async {
await audio.load();
audio.backgroundMusic();
await Future.wait(player.load());
player.play(PinballAudio.backgroundMusic);
verify(
() => loopSingleAudio
@ -238,5 +238,15 @@ void main() {
).called(1);
});
});
test(
'throws assertions error when playing an unregistered audio',
() async {
player.audios.remove(PinballAudio.google);
await Future.wait(player.load());
expect(() => player.play(PinballAudio.google), throwsAssertionError);
},
);
});
}

@ -9,7 +9,7 @@ import 'package:pinball_audio/pinball_audio.dart';
class _MockAuthenticationRepository extends Mock
implements AuthenticationRepository {}
class _MockPinballAudio extends Mock implements PinballAudio {}
class _MockPinballPlayer extends Mock implements PinballPlayer {}
class _MockLeaderboardRepository extends Mock implements LeaderboardRepository {
}
@ -18,13 +18,13 @@ void main() {
group('App', () {
late AuthenticationRepository authenticationRepository;
late LeaderboardRepository leaderboardRepository;
late PinballAudio pinballAudio;
late PinballPlayer pinballPlayer;
setUp(() {
authenticationRepository = _MockAuthenticationRepository();
leaderboardRepository = _MockLeaderboardRepository();
pinballAudio = _MockPinballAudio();
when(pinballAudio.load).thenAnswer((_) => Future.value());
pinballPlayer = _MockPinballPlayer();
when(pinballPlayer.load).thenAnswer((_) => [Future.value()]);
});
testWidgets('renders PinballGamePage', (tester) async {
@ -32,7 +32,7 @@ void main() {
App(
authenticationRepository: authenticationRepository,
leaderboardRepository: leaderboardRepository,
pinballAudio: pinballAudio,
pinballPlayer: pinballPlayer,
),
);
expect(find.byType(PinballGamePage), findsOneWidget);

@ -16,7 +16,7 @@ class _TestBodyComponent extends BodyComponent {
}
}
class _MockPinballAudio extends Mock implements PinballAudio {}
class _MockPinballPlayer extends Mock implements PinballPlayer {}
class _MockContact extends Mock implements Contact {}
@ -25,13 +25,13 @@ void main() {
group('BumperNoisyBehavior', () {});
late PinballAudio audio;
late PinballPlayer player;
final flameTester = FlameTester(
() => EmptyPinballTestGame(audio: audio),
() => EmptyPinballTestGame(player: player),
);
setUp(() {
audio = _MockPinballAudio();
player = _MockPinballPlayer();
});
flameTester.testGameWidget(
@ -44,7 +44,7 @@ void main() {
behavior.beginContact(Object(), _MockContact());
},
verify: (_, __) async {
verify(audio.bumper).called(1);
verify(() => player.play(PinballAudio.bumper)).called(1);
},
);
}

@ -16,7 +16,7 @@ class _MockCameraController extends Mock implements CameraController {}
class _MockActiveOverlaysNotifier extends Mock
implements ActiveOverlaysNotifier {}
class _MockPinballAudio extends Mock implements PinballAudio {}
class _MockPinballPlayer extends Mock implements PinballPlayer {}
void main() {
group('GameFlowController', () {
@ -43,7 +43,7 @@ void main() {
late Backbox backbox;
late CameraController cameraController;
late GameFlowController gameFlowController;
late PinballAudio pinballAudio;
late PinballPlayer pinballPlayer;
late ActiveOverlaysNotifier overlays;
setUp(() {
@ -52,7 +52,7 @@ void main() {
cameraController = _MockCameraController();
gameFlowController = GameFlowController(game);
overlays = _MockActiveOverlaysNotifier();
pinballAudio = _MockPinballAudio();
pinballPlayer = _MockPinballPlayer();
when(
() => backbox.initialsInput(
@ -71,7 +71,7 @@ void main() {
when(game.firstChild<CameraController>).thenReturn(cameraController);
when(() => game.overlays).thenReturn(overlays);
when(() => game.characterTheme).thenReturn(DashTheme());
when(() => game.audio).thenReturn(pinballAudio);
when(() => game.player).thenReturn(pinballPlayer);
});
test(
@ -115,7 +115,8 @@ void main() {
() {
gameFlowController.onNewState(GameState.initial());
verify(pinballAudio.backgroundMusic).called(1);
verify(() => pinballPlayer.play(PinballAudio.backgroundMusic))
.called(1);
},
);
});

@ -24,12 +24,12 @@ class _MockGameBloc extends Mock implements GameBloc {}
class _MockStartGameBloc extends Mock implements StartGameBloc {}
class _MockPinballAudio extends Mock implements PinballAudio {}
class _MockPinballPlayer extends Mock implements PinballPlayer {}
PinballAudio _buildDefaultPinballAudio() {
final audio = _MockPinballAudio();
when(audio.load).thenAnswer((_) => Future.value());
return audio;
PinballPlayer _buildDefaultPinballPlayer() {
final player = _MockPinballPlayer();
when(player.load).thenAnswer((_) => [Future.value()]);
return player;
}
AssetsManagerCubit _buildDefaultAssetsManagerCubit() {
@ -55,7 +55,7 @@ extension PumpApp on WidgetTester {
AssetsManagerCubit? assetsManagerCubit,
CharacterThemeCubit? characterThemeCubit,
LeaderboardRepository? leaderboardRepository,
PinballAudio? pinballAudio,
PinballPlayer? pinballPlayer,
}) {
return runAsync(() {
return pumpWidget(
@ -65,7 +65,7 @@ extension PumpApp on WidgetTester {
value: leaderboardRepository ?? _MockLeaderboardRepository(),
),
RepositoryProvider.value(
value: pinballAudio ?? _buildDefaultPinballAudio(),
value: pinballPlayer ?? _buildDefaultPinballPlayer(),
),
],
child: MultiBlocProvider(

@ -11,7 +11,7 @@ import 'package:pinball/l10n/l10n.dart';
import 'package:pinball_audio/pinball_audio.dart';
import 'package:pinball_theme/pinball_theme.dart';
class _MockPinballAudio extends Mock implements PinballAudio {}
class _MockPinballPlayer extends Mock implements PinballPlayer {}
class _MockAppLocalizations extends Mock implements AppLocalizations {}
@ -24,12 +24,12 @@ class TestGame extends Forge2DGame with FlameBloc {
class PinballTestGame extends PinballGame {
PinballTestGame({
List<String>? assets,
PinballAudio? audio,
PinballPlayer? player,
CharacterTheme? theme,
AppLocalizations? l10n,
}) : _assets = assets,
super(
audio: audio ?? _MockPinballAudio(),
player: player ?? _MockPinballPlayer(),
characterTheme: theme ?? const DashTheme(),
l10n: l10n ?? _MockAppLocalizations(),
);
@ -47,12 +47,12 @@ class PinballTestGame extends PinballGame {
class DebugPinballTestGame extends DebugPinballGame {
DebugPinballTestGame({
List<String>? assets,
PinballAudio? audio,
PinballPlayer? player,
CharacterTheme? theme,
AppLocalizations? l10n,
}) : _assets = assets,
super(
audio: audio ?? _MockPinballAudio(),
player: player ?? _MockPinballPlayer(),
characterTheme: theme ?? const DashTheme(),
l10n: l10n ?? _MockAppLocalizations(),
);
@ -71,12 +71,12 @@ class DebugPinballTestGame extends DebugPinballGame {
class EmptyPinballTestGame extends PinballTestGame {
EmptyPinballTestGame({
List<String>? assets,
PinballAudio? audio,
PinballPlayer? player,
CharacterTheme? theme,
AppLocalizations? l10n,
}) : super(
assets: assets,
audio: audio,
player: player,
theme: theme,
l10n: l10n ?? _MockAppLocalizations(),
);
@ -93,12 +93,12 @@ class EmptyKeyboardPinballTestGame extends PinballTestGame
with HasKeyboardHandlerComponents {
EmptyKeyboardPinballTestGame({
List<String>? assets,
PinballAudio? audio,
PinballPlayer? player,
CharacterTheme? theme,
AppLocalizations? l10n,
}) : super(
assets: assets,
audio: audio,
player: player,
theme: theme,
l10n: l10n ?? _MockAppLocalizations(),
);

@ -18,12 +18,12 @@ class _MockPinballGame extends Mock implements PinballGame {}
class _MockGameFlowController extends Mock implements GameFlowController {}
class _MockPinballAudio extends Mock implements PinballAudio {}
class _MockPinballPlayer extends Mock implements PinballPlayer {}
void main() {
late StartGameBloc startGameBloc;
late PinballGame pinballGame;
late PinballAudio pinballAudio;
late PinballPlayer pinballPlayer;
late CharacterThemeCubit characterThemeCubit;
group('StartGameListener', () {
@ -32,7 +32,7 @@ void main() {
startGameBloc = _MockStartGameBloc();
pinballGame = _MockPinballGame();
pinballAudio = _MockPinballAudio();
pinballPlayer = _MockPinballPlayer();
characterThemeCubit = _MockCharacterThemeCubit();
});
@ -244,7 +244,7 @@ void main() {
child: const SizedBox.shrink(),
),
startGameBloc: startGameBloc,
pinballAudio: pinballAudio,
pinballPlayer: pinballPlayer,
);
await tester.pumpAndSettle();
@ -261,7 +261,8 @@ void main() {
);
await tester.pumpAndSettle();
verify(pinballAudio.ioPinballVoiceOver).called(1);
verify(() => pinballPlayer.play(PinballAudio.ioPinballVoiceOver))
.called(1);
},
);
});

Loading…
Cancel
Save