feat: throttle assets loading for more stability (#443)

* feat: throttle assets loading for more stability

* lint

* coveragE

* chore: remove instances of e

Co-authored-by: Allison Ryan <allisonryan0002@gmail.com>
pull/447/head
Erick 3 years ago committed by GitHub
parent 4ad59a795a
commit 5e8ac20d37
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -19,21 +19,31 @@ class AssetsManagerCubit extends Cubit<AssetsManagerState> {
/// do its job without adding too much delay for the user, we are letting /// do its job without adding too much delay for the user, we are letting
/// the UI paint first, and then we start loading the assets. /// the UI paint first, and then we start loading the assets.
await Future<void>.delayed(const Duration(seconds: 1)); await Future<void>.delayed(const Duration(seconds: 1));
emit( final loadables = <Future<void> Function()>[
state.copyWith( _game.preFetchLeaderboard,
loadables: [
_game.preFetchLeaderboard(),
..._game.preLoadAssets(), ..._game.preLoadAssets(),
..._audioPlayer.load(), ..._audioPlayer.load(),
...BonusAnimation.loadAssets(), ...BonusAnimation.loadAssets(),
...SelectedCharacter.loadAssets(), ...SelectedCharacter.loadAssets(),
], ];
emit(
state.copyWith(
assetsCount: loadables.length,
), ),
); );
final all = state.loadables.map((loadable) async {
await loadable; late void Function() _triggerLoad;
emit(state.copyWith(loaded: [...state.loaded, loadable])); _triggerLoad = () async {
}).toList(); if (loadables.isEmpty) return;
await Future.wait(all); final loadable = loadables.removeAt(0);
await loadable();
_triggerLoad();
emit(state.copyWith(loaded: state.loaded + 1));
};
const _throttleSize = 3;
for (var i = 0; i < _throttleSize; i++) {
_triggerLoad();
}
} }
} }

@ -1,44 +1,42 @@
part of 'assets_manager_cubit.dart'; part of 'assets_manager_cubit.dart';
/// {@template assets_manager_state} /// {@template assets_manager_state}
/// State used to load the game assets /// State used to load the game assets.
/// {@endtemplate} /// {@endtemplate}
class AssetsManagerState extends Equatable { class AssetsManagerState extends Equatable {
/// {@macro assets_manager_state} /// {@macro assets_manager_state}
const AssetsManagerState({ const AssetsManagerState({
required this.loadables, required this.assetsCount,
required this.loaded, required this.loaded,
}); });
/// {@macro assets_manager_state} /// {@macro assets_manager_state}
const AssetsManagerState.initial() const AssetsManagerState.initial() : this(assetsCount: 0, loaded: 0);
: this(loadables: const [], loaded: const []);
/// List of futures to load /// Number of assets to load.
final List<Future> loadables; final int assetsCount;
/// List of loaded futures /// Number of already loaded assets.
final List<Future> loaded; final int loaded;
/// Returns a value between 0 and 1 to indicate the loading progress /// Returns a value between 0 and 1 to indicate the loading progress.
double get progress => double get progress => loaded == 0 ? 0 : loaded / assetsCount;
loadables.isEmpty ? 0 : loaded.length / loadables.length;
/// Only returns false if all the assets have been loaded /// Only returns false if all the assets have been loaded.
bool get isLoading => progress != 1; bool get isLoading => progress != 1;
/// Returns a copy of this instance with the given parameters /// Returns a copy of this instance with the given parameters
/// updated /// updated.
AssetsManagerState copyWith({ AssetsManagerState copyWith({
List<Future>? loadables, int? assetsCount,
List<Future>? loaded, int? loaded,
}) { }) {
return AssetsManagerState( return AssetsManagerState(
loadables: loadables ?? this.loadables, assetsCount: assetsCount ?? this.assetsCount,
loaded: loaded ?? this.loaded, loaded: loaded ?? this.loaded,
); );
} }
@override @override
List<Object> get props => [loaded, loadables]; List<Object> get props => [loaded, assetsCount];
} }

@ -6,158 +6,196 @@ import 'package:pinball_theme/pinball_theme.dart' hide Assets;
/// Add methods to help loading and caching game assets. /// Add methods to help loading and caching game assets.
extension PinballGameAssetsX on PinballGame { extension PinballGameAssetsX on PinballGame {
/// Returns a list of assets to be loaded /// Returns a list of assets to be loaded
List<Future<Image>> preLoadAssets() { List<Future<Image> Function()> preLoadAssets() {
const dashTheme = DashTheme(); const dashTheme = DashTheme();
const sparkyTheme = SparkyTheme(); const sparkyTheme = SparkyTheme();
const androidTheme = AndroidTheme(); const androidTheme = AndroidTheme();
const dinoTheme = DinoTheme(); const dinoTheme = DinoTheme();
return [ return [
images.load(components.Assets.images.boardBackground.keyName), () => images.load(components.Assets.images.boardBackground.keyName),
images.load(components.Assets.images.ball.flameEffect.keyName), () => images.load(components.Assets.images.ball.flameEffect.keyName),
images.load(components.Assets.images.signpost.inactive.keyName), () => images.load(components.Assets.images.signpost.inactive.keyName),
images.load(components.Assets.images.signpost.active1.keyName), () => images.load(components.Assets.images.signpost.active1.keyName),
images.load(components.Assets.images.signpost.active2.keyName), () => images.load(components.Assets.images.signpost.active2.keyName),
images.load(components.Assets.images.signpost.active3.keyName), () => images.load(components.Assets.images.signpost.active3.keyName),
images.load(components.Assets.images.flipper.left.keyName), () => images.load(components.Assets.images.flipper.left.keyName),
images.load(components.Assets.images.flipper.right.keyName), () => images.load(components.Assets.images.flipper.right.keyName),
images.load(components.Assets.images.baseboard.left.keyName), () => images.load(components.Assets.images.baseboard.left.keyName),
images.load(components.Assets.images.baseboard.right.keyName), () => images.load(components.Assets.images.baseboard.right.keyName),
images.load(components.Assets.images.kicker.left.lit.keyName), () => images.load(components.Assets.images.kicker.left.lit.keyName),
images.load(components.Assets.images.kicker.left.dimmed.keyName), () => images.load(components.Assets.images.kicker.left.dimmed.keyName),
images.load(components.Assets.images.kicker.right.lit.keyName), () => images.load(components.Assets.images.kicker.right.lit.keyName),
images.load(components.Assets.images.kicker.right.dimmed.keyName), () => images.load(components.Assets.images.kicker.right.dimmed.keyName),
images.load(components.Assets.images.slingshot.upper.keyName), () => images.load(components.Assets.images.slingshot.upper.keyName),
images.load(components.Assets.images.slingshot.lower.keyName), () => images.load(components.Assets.images.slingshot.lower.keyName),
images.load(components.Assets.images.launchRamp.ramp.keyName), () => images.load(components.Assets.images.launchRamp.ramp.keyName),
images.load( () => images.load(
components.Assets.images.launchRamp.foregroundRailing.keyName, components.Assets.images.launchRamp.foregroundRailing.keyName,
), ),
images.load( () => images.load(
components.Assets.images.launchRamp.backgroundRailing.keyName, components.Assets.images.launchRamp.backgroundRailing.keyName,
), ),
images.load(components.Assets.images.dino.bottomWall.keyName), () => images.load(components.Assets.images.dino.bottomWall.keyName),
images.load(components.Assets.images.dino.topWall.keyName), () => images.load(components.Assets.images.dino.topWall.keyName),
images.load(components.Assets.images.dino.topWallTunnel.keyName), () => images.load(components.Assets.images.dino.topWallTunnel.keyName),
images.load(components.Assets.images.dino.animatronic.head.keyName), () => images.load(components.Assets.images.dino.animatronic.head.keyName),
() =>
images.load(components.Assets.images.dino.animatronic.mouth.keyName), images.load(components.Assets.images.dino.animatronic.mouth.keyName),
images.load(components.Assets.images.dash.animatronic.keyName), () => images.load(components.Assets.images.dash.animatronic.keyName),
images.load(components.Assets.images.dash.bumper.a.active.keyName), () => images.load(components.Assets.images.dash.bumper.a.active.keyName),
() =>
images.load(components.Assets.images.dash.bumper.a.inactive.keyName), images.load(components.Assets.images.dash.bumper.a.inactive.keyName),
images.load(components.Assets.images.dash.bumper.b.active.keyName), () => images.load(components.Assets.images.dash.bumper.b.active.keyName),
() =>
images.load(components.Assets.images.dash.bumper.b.inactive.keyName), images.load(components.Assets.images.dash.bumper.b.inactive.keyName),
() =>
images.load(components.Assets.images.dash.bumper.main.active.keyName), images.load(components.Assets.images.dash.bumper.main.active.keyName),
images.load(components.Assets.images.dash.bumper.main.inactive.keyName), () => images
images.load(components.Assets.images.plunger.plunger.keyName), .load(components.Assets.images.dash.bumper.main.inactive.keyName),
images.load(components.Assets.images.plunger.rocket.keyName), () => images.load(components.Assets.images.plunger.plunger.keyName),
images.load(components.Assets.images.boundary.bottom.keyName), () => images.load(components.Assets.images.plunger.rocket.keyName),
images.load(components.Assets.images.boundary.outer.keyName), () => images.load(components.Assets.images.boundary.bottom.keyName),
images.load(components.Assets.images.boundary.outerBottom.keyName), () => images.load(components.Assets.images.boundary.outer.keyName),
images.load(components.Assets.images.android.spaceship.saucer.keyName), () => images.load(components.Assets.images.boundary.outerBottom.keyName),
images () => images
.load(components.Assets.images.android.spaceship.saucer.keyName),
() => images
.load(components.Assets.images.android.spaceship.animatronic.keyName), .load(components.Assets.images.android.spaceship.animatronic.keyName),
images.load(components.Assets.images.android.spaceship.lightBeam.keyName), () => images
images.load(components.Assets.images.android.ramp.boardOpening.keyName), .load(components.Assets.images.android.spaceship.lightBeam.keyName),
images.load( () => images
.load(components.Assets.images.android.ramp.boardOpening.keyName),
() => images.load(
components.Assets.images.android.ramp.railingForeground.keyName, components.Assets.images.android.ramp.railingForeground.keyName,
), ),
images.load( () => images.load(
components.Assets.images.android.ramp.railingBackground.keyName, components.Assets.images.android.ramp.railingBackground.keyName,
), ),
images.load(components.Assets.images.android.ramp.main.keyName), () => images.load(components.Assets.images.android.ramp.main.keyName),
images.load(components.Assets.images.android.ramp.arrow.inactive.keyName), () => images
images.load( .load(components.Assets.images.android.ramp.arrow.inactive.keyName),
() => images.load(
components.Assets.images.android.ramp.arrow.active1.keyName, components.Assets.images.android.ramp.arrow.active1.keyName,
), ),
images.load( () => images.load(
components.Assets.images.android.ramp.arrow.active2.keyName, components.Assets.images.android.ramp.arrow.active2.keyName,
), ),
images.load( () => images.load(
components.Assets.images.android.ramp.arrow.active3.keyName, components.Assets.images.android.ramp.arrow.active3.keyName,
), ),
images.load( () => images.load(
components.Assets.images.android.ramp.arrow.active4.keyName, components.Assets.images.android.ramp.arrow.active4.keyName,
), ),
images.load( () => images.load(
components.Assets.images.android.ramp.arrow.active5.keyName, components.Assets.images.android.ramp.arrow.active5.keyName,
), ),
images.load(components.Assets.images.android.rail.main.keyName), () => images.load(components.Assets.images.android.rail.main.keyName),
images.load(components.Assets.images.android.rail.exit.keyName), () => images.load(components.Assets.images.android.rail.exit.keyName),
images.load(components.Assets.images.android.bumper.a.lit.keyName), () => images.load(components.Assets.images.android.bumper.a.lit.keyName),
() =>
images.load(components.Assets.images.android.bumper.a.dimmed.keyName), images.load(components.Assets.images.android.bumper.a.dimmed.keyName),
images.load(components.Assets.images.android.bumper.b.lit.keyName), () => images.load(components.Assets.images.android.bumper.b.lit.keyName),
() =>
images.load(components.Assets.images.android.bumper.b.dimmed.keyName), images.load(components.Assets.images.android.bumper.b.dimmed.keyName),
() =>
images.load(components.Assets.images.android.bumper.cow.lit.keyName), images.load(components.Assets.images.android.bumper.cow.lit.keyName),
images.load(components.Assets.images.android.bumper.cow.dimmed.keyName), () => images
images.load(components.Assets.images.sparky.computer.top.keyName), .load(components.Assets.images.android.bumper.cow.dimmed.keyName),
images.load(components.Assets.images.sparky.computer.base.keyName), () => images.load(components.Assets.images.sparky.computer.top.keyName),
images.load(components.Assets.images.sparky.computer.glow.keyName), () => images.load(components.Assets.images.sparky.computer.base.keyName),
images.load(components.Assets.images.sparky.animatronic.keyName), () => images.load(components.Assets.images.sparky.computer.glow.keyName),
images.load(components.Assets.images.sparky.bumper.a.lit.keyName), () => images.load(components.Assets.images.sparky.animatronic.keyName),
() => images.load(components.Assets.images.sparky.bumper.a.lit.keyName),
() =>
images.load(components.Assets.images.sparky.bumper.a.dimmed.keyName), images.load(components.Assets.images.sparky.bumper.a.dimmed.keyName),
images.load(components.Assets.images.sparky.bumper.b.lit.keyName), () => images.load(components.Assets.images.sparky.bumper.b.lit.keyName),
() =>
images.load(components.Assets.images.sparky.bumper.b.dimmed.keyName), images.load(components.Assets.images.sparky.bumper.b.dimmed.keyName),
images.load(components.Assets.images.sparky.bumper.c.lit.keyName), () => images.load(components.Assets.images.sparky.bumper.c.lit.keyName),
() =>
images.load(components.Assets.images.sparky.bumper.c.dimmed.keyName), images.load(components.Assets.images.sparky.bumper.c.dimmed.keyName),
images.load(components.Assets.images.backbox.marquee.keyName), () => images.load(components.Assets.images.backbox.marquee.keyName),
() =>
images.load(components.Assets.images.backbox.displayDivider.keyName), images.load(components.Assets.images.backbox.displayDivider.keyName),
() =>
images.load(components.Assets.images.backbox.button.facebook.keyName), images.load(components.Assets.images.backbox.button.facebook.keyName),
() =>
images.load(components.Assets.images.backbox.button.twitter.keyName), images.load(components.Assets.images.backbox.button.twitter.keyName),
images.load( () => images.load(
components.Assets.images.backbox.displayTitleDecoration.keyName, components.Assets.images.backbox.displayTitleDecoration.keyName,
), ),
() =>
images.load(components.Assets.images.googleWord.letter1.lit.keyName), images.load(components.Assets.images.googleWord.letter1.lit.keyName),
images.load(components.Assets.images.googleWord.letter1.dimmed.keyName), () => images
.load(components.Assets.images.googleWord.letter1.dimmed.keyName),
() =>
images.load(components.Assets.images.googleWord.letter2.lit.keyName), images.load(components.Assets.images.googleWord.letter2.lit.keyName),
images.load(components.Assets.images.googleWord.letter2.dimmed.keyName), () => images
.load(components.Assets.images.googleWord.letter2.dimmed.keyName),
() =>
images.load(components.Assets.images.googleWord.letter3.lit.keyName), images.load(components.Assets.images.googleWord.letter3.lit.keyName),
images.load(components.Assets.images.googleWord.letter3.dimmed.keyName), () => images
.load(components.Assets.images.googleWord.letter3.dimmed.keyName),
() =>
images.load(components.Assets.images.googleWord.letter4.lit.keyName), images.load(components.Assets.images.googleWord.letter4.lit.keyName),
images.load(components.Assets.images.googleWord.letter4.dimmed.keyName), () => images
.load(components.Assets.images.googleWord.letter4.dimmed.keyName),
() =>
images.load(components.Assets.images.googleWord.letter5.lit.keyName), images.load(components.Assets.images.googleWord.letter5.lit.keyName),
images.load(components.Assets.images.googleWord.letter5.dimmed.keyName), () => images
.load(components.Assets.images.googleWord.letter5.dimmed.keyName),
() =>
images.load(components.Assets.images.googleWord.letter6.lit.keyName), images.load(components.Assets.images.googleWord.letter6.lit.keyName),
images.load(components.Assets.images.googleWord.letter6.dimmed.keyName), () => images
images.load(components.Assets.images.googleRollover.left.decal.keyName), .load(components.Assets.images.googleWord.letter6.dimmed.keyName),
() => images
.load(components.Assets.images.googleRollover.left.decal.keyName),
() =>
images.load(components.Assets.images.googleRollover.left.pin.keyName), images.load(components.Assets.images.googleRollover.left.pin.keyName),
images.load(components.Assets.images.googleRollover.right.decal.keyName), () => images
images.load(components.Assets.images.googleRollover.right.pin.keyName), .load(components.Assets.images.googleRollover.right.decal.keyName),
images.load(components.Assets.images.multiball.lit.keyName), () => images
images.load(components.Assets.images.multiball.dimmed.keyName), .load(components.Assets.images.googleRollover.right.pin.keyName),
images.load(components.Assets.images.multiplier.x2.lit.keyName), () => images.load(components.Assets.images.multiball.lit.keyName),
images.load(components.Assets.images.multiplier.x2.dimmed.keyName), () => images.load(components.Assets.images.multiball.dimmed.keyName),
images.load(components.Assets.images.multiplier.x3.lit.keyName), () => images.load(components.Assets.images.multiplier.x2.lit.keyName),
images.load(components.Assets.images.multiplier.x3.dimmed.keyName), () => images.load(components.Assets.images.multiplier.x2.dimmed.keyName),
images.load(components.Assets.images.multiplier.x4.lit.keyName), () => images.load(components.Assets.images.multiplier.x3.lit.keyName),
images.load(components.Assets.images.multiplier.x4.dimmed.keyName), () => images.load(components.Assets.images.multiplier.x3.dimmed.keyName),
images.load(components.Assets.images.multiplier.x5.lit.keyName), () => images.load(components.Assets.images.multiplier.x4.lit.keyName),
images.load(components.Assets.images.multiplier.x5.dimmed.keyName), () => images.load(components.Assets.images.multiplier.x4.dimmed.keyName),
images.load(components.Assets.images.multiplier.x6.lit.keyName), () => images.load(components.Assets.images.multiplier.x5.lit.keyName),
images.load(components.Assets.images.multiplier.x6.dimmed.keyName), () => images.load(components.Assets.images.multiplier.x5.dimmed.keyName),
images.load(components.Assets.images.score.fiveThousand.keyName), () => images.load(components.Assets.images.multiplier.x6.lit.keyName),
images.load(components.Assets.images.score.twentyThousand.keyName), () => images.load(components.Assets.images.multiplier.x6.dimmed.keyName),
images.load(components.Assets.images.score.twoHundredThousand.keyName), () => images.load(components.Assets.images.score.fiveThousand.keyName),
images.load(components.Assets.images.score.oneMillion.keyName), () => images.load(components.Assets.images.score.twentyThousand.keyName),
images.load(components.Assets.images.flapper.backSupport.keyName), () => images
images.load(components.Assets.images.flapper.frontSupport.keyName), .load(components.Assets.images.score.twoHundredThousand.keyName),
images.load(components.Assets.images.flapper.flap.keyName), () => images.load(components.Assets.images.score.oneMillion.keyName),
images.load(components.Assets.images.skillShot.decal.keyName), () => images.load(components.Assets.images.flapper.backSupport.keyName),
images.load(components.Assets.images.skillShot.pin.keyName), () => images.load(components.Assets.images.flapper.frontSupport.keyName),
images.load(components.Assets.images.skillShot.lit.keyName), () => images.load(components.Assets.images.flapper.flap.keyName),
images.load(components.Assets.images.skillShot.dimmed.keyName), () => images.load(components.Assets.images.skillShot.decal.keyName),
() => images.load(components.Assets.images.skillShot.pin.keyName),
() => images.load(components.Assets.images.skillShot.lit.keyName),
() => images.load(components.Assets.images.skillShot.dimmed.keyName),
() =>
images.load(components.Assets.images.displayArrows.arrowLeft.keyName), images.load(components.Assets.images.displayArrows.arrowLeft.keyName),
images.load(components.Assets.images.displayArrows.arrowRight.keyName), () => images
images.load(androidTheme.leaderboardIcon.keyName), .load(components.Assets.images.displayArrows.arrowRight.keyName),
images.load(androidTheme.ball.keyName), () => images.load(androidTheme.leaderboardIcon.keyName),
images.load(dashTheme.leaderboardIcon.keyName), () => images.load(androidTheme.ball.keyName),
images.load(dashTheme.ball.keyName), () => images.load(dashTheme.leaderboardIcon.keyName),
images.load(dinoTheme.leaderboardIcon.keyName), () => images.load(dashTheme.ball.keyName),
images.load(dinoTheme.ball.keyName), () => images.load(dinoTheme.leaderboardIcon.keyName),
images.load(sparkyTheme.leaderboardIcon.keyName), () => images.load(dinoTheme.ball.keyName),
images.load(sparkyTheme.ball.keyName), () => images.load(sparkyTheme.leaderboardIcon.keyName),
images.load(androidTheme.background.keyName), () => images.load(sparkyTheme.ball.keyName),
images.load(dashTheme.background.keyName), () => images.load(androidTheme.background.keyName),
images.load(dinoTheme.background.keyName), () => images.load(dashTheme.background.keyName),
images.load(sparkyTheme.background.keyName), () => images.load(dinoTheme.background.keyName),
() => images.load(sparkyTheme.background.keyName),
]; ];
} }
} }

@ -72,14 +72,16 @@ class BonusAnimation extends StatefulWidget {
final VoidCallback? _onCompleted; final VoidCallback? _onCompleted;
/// Returns a list of assets to be loaded for animations. /// Returns a list of assets to be loaded for animations.
static List<Future> loadAssets() { static List<Future Function()> loadAssets() {
Flame.images.prefix = ''; Flame.images.prefix = '';
return [ return [
Flame.images.load(Assets.images.bonusAnimation.dashNest.keyName), () => Flame.images.load(Assets.images.bonusAnimation.dashNest.keyName),
Flame.images.load(Assets.images.bonusAnimation.sparkyTurboCharge.keyName), () => Flame.images
Flame.images.load(Assets.images.bonusAnimation.dinoChomp.keyName), .load(Assets.images.bonusAnimation.sparkyTurboCharge.keyName),
Flame.images.load(Assets.images.bonusAnimation.androidSpaceship.keyName), () => Flame.images.load(Assets.images.bonusAnimation.dinoChomp.keyName),
Flame.images.load(Assets.images.bonusAnimation.googleWord.keyName), () => Flame.images
.load(Assets.images.bonusAnimation.androidSpaceship.keyName),
() => Flame.images.load(Assets.images.bonusAnimation.googleWord.keyName),
]; ];
} }

@ -22,12 +22,12 @@ class SelectedCharacter extends StatefulWidget {
State<SelectedCharacter> createState() => _SelectedCharacterState(); State<SelectedCharacter> createState() => _SelectedCharacterState();
/// Returns a list of assets to be loaded. /// Returns a list of assets to be loaded.
static List<Future> loadAssets() { static List<Future Function()> loadAssets() {
return [ return [
Flame.images.load(const DashTheme().animation.keyName), () => Flame.images.load(const DashTheme().animation.keyName),
Flame.images.load(const AndroidTheme().animation.keyName), () => Flame.images.load(const AndroidTheme().animation.keyName),
Flame.images.load(const DinoTheme().animation.keyName), () => Flame.images.load(const DinoTheme().animation.keyName),
Flame.images.load(const SparkyTheme().animation.keyName), () => Flame.images.load(const SparkyTheme().animation.keyName),
]; ];
} }
} }

@ -334,10 +334,10 @@ class PinballAudioPlayer {
late final Map<PinballAudio, _Audio> audios; late final Map<PinballAudio, _Audio> audios;
/// Loads the sounds effects into the memory. /// Loads the sounds effects into the memory.
List<Future<void>> load() { List<Future<void> Function()> load() {
_configureAudioCache(FlameAudio.audioCache); _configureAudioCache(FlameAudio.audioCache);
return audios.values.map((a) => a.load()).toList(); return audios.values.map((a) => a.load).toList();
} }
/// Plays the received audio. /// Plays the received audio.

@ -102,7 +102,9 @@ void main() {
group('load', () { group('load', () {
test('creates the bumpers pools', () async { test('creates the bumpers pools', () async {
await Future.wait(audioPlayer.load()); await Future.wait(
audioPlayer.load().map((loadableBuilder) => loadableBuilder()),
);
verify( verify(
() => createAudioPool.onCall( () => createAudioPool.onCall(
@ -122,7 +124,9 @@ void main() {
}); });
test('creates the kicker pools', () async { test('creates the kicker pools', () async {
await Future.wait(audioPlayer.load()); await Future.wait(
audioPlayer.load().map((loadableBuilder) => loadableBuilder()),
);
verify( verify(
() => createAudioPool.onCall( () => createAudioPool.onCall(
@ -142,7 +146,9 @@ void main() {
}); });
test('configures the audio cache instance', () async { test('configures the audio cache instance', () async {
await Future.wait(audioPlayer.load()); await Future.wait(
audioPlayer.load().map((loadableBuilder) => loadableBuilder()),
);
verify(() => configureAudioCache.onCall(FlameAudio.audioCache)) verify(() => configureAudioCache.onCall(FlameAudio.audioCache))
.called(1); .called(1);
@ -154,13 +160,17 @@ void main() {
playSingleAudio: playSingleAudio.onCall, playSingleAudio: playSingleAudio.onCall,
preCacheSingleAudio: preCacheSingleAudio.onCall, preCacheSingleAudio: preCacheSingleAudio.onCall,
); );
await Future.wait(audioPlayer.load()); await Future.wait(
audioPlayer.load().map((loadableBuilder) => loadableBuilder()),
);
expect(FlameAudio.audioCache.prefix, equals('')); expect(FlameAudio.audioCache.prefix, equals(''));
}); });
test('pre cache the assets', () async { test('pre cache the assets', () async {
await Future.wait(audioPlayer.load()); await Future.wait(
audioPlayer.load().map((loadableBuilder) => loadableBuilder()),
);
verify( verify(
() => preCacheSingleAudio () => preCacheSingleAudio
@ -242,7 +252,9 @@ void main() {
group('when seed is true', () { group('when seed is true', () {
test('plays the bumper A sound pool', () async { test('plays the bumper A sound pool', () async {
when(seed.nextBool).thenReturn(true); when(seed.nextBool).thenReturn(true);
await Future.wait(audioPlayer.load()); await Future.wait(
audioPlayer.load().map((loadableBuilder) => loadableBuilder()),
);
audioPlayer.play(PinballAudio.bumper); audioPlayer.play(PinballAudio.bumper);
verify(() => bumperAPool.start(volume: 0.6)).called(1); verify(() => bumperAPool.start(volume: 0.6)).called(1);
@ -252,7 +264,9 @@ void main() {
group('when seed is false', () { group('when seed is false', () {
test('plays the bumper B sound pool', () async { test('plays the bumper B sound pool', () async {
when(seed.nextBool).thenReturn(false); when(seed.nextBool).thenReturn(false);
await Future.wait(audioPlayer.load()); await Future.wait(
audioPlayer.load().map((loadableBuilder) => loadableBuilder()),
);
audioPlayer.play(PinballAudio.bumper); audioPlayer.play(PinballAudio.bumper);
verify(() => bumperBPool.start(volume: 0.6)).called(1); verify(() => bumperBPool.start(volume: 0.6)).called(1);
@ -291,7 +305,9 @@ void main() {
group('when seed is true', () { group('when seed is true', () {
test('plays the kicker A sound pool', () async { test('plays the kicker A sound pool', () async {
when(seed.nextBool).thenReturn(true); when(seed.nextBool).thenReturn(true);
await Future.wait(audioPlayer.load()); await Future.wait(
audioPlayer.load().map((loadableBuilder) => loadableBuilder()),
);
audioPlayer.play(PinballAudio.kicker); audioPlayer.play(PinballAudio.kicker);
verify(() => kickerAPool.start(volume: 0.6)).called(1); verify(() => kickerAPool.start(volume: 0.6)).called(1);
@ -301,7 +317,9 @@ void main() {
group('when seed is false', () { group('when seed is false', () {
test('plays the kicker B sound pool', () async { test('plays the kicker B sound pool', () async {
when(seed.nextBool).thenReturn(false); when(seed.nextBool).thenReturn(false);
await Future.wait(audioPlayer.load()); await Future.wait(
audioPlayer.load().map((loadableBuilder) => loadableBuilder()),
);
audioPlayer.play(PinballAudio.kicker); audioPlayer.play(PinballAudio.kicker);
verify(() => kickerBPool.start(volume: 0.6)).called(1); verify(() => kickerBPool.start(volume: 0.6)).called(1);
@ -311,7 +329,9 @@ void main() {
group('cow moo', () { group('cow moo', () {
test('plays the correct file', () async { test('plays the correct file', () async {
await Future.wait(audioPlayer.load()); await Future.wait(
audioPlayer.load().map((loadableBuilder) => loadableBuilder()),
);
audioPlayer.play(PinballAudio.cowMoo); audioPlayer.play(PinballAudio.cowMoo);
verify( verify(
@ -324,7 +344,9 @@ void main() {
final clock = _MockClock(); final clock = _MockClock();
await withClock(clock, () async { await withClock(clock, () async {
when(clock.now).thenReturn(DateTime(2022)); when(clock.now).thenReturn(DateTime(2022));
await Future.wait(audioPlayer.load()); await Future.wait(
audioPlayer.load().map((loadableBuilder) => loadableBuilder()),
);
audioPlayer audioPlayer
..play(PinballAudio.cowMoo) ..play(PinballAudio.cowMoo)
..play(PinballAudio.cowMoo); ..play(PinballAudio.cowMoo);
@ -347,7 +369,9 @@ void main() {
group('google', () { group('google', () {
test('plays the correct file', () async { test('plays the correct file', () async {
await Future.wait(audioPlayer.load()); await Future.wait(
audioPlayer.load().map((loadableBuilder) => loadableBuilder()),
);
audioPlayer.play(PinballAudio.google); audioPlayer.play(PinballAudio.google);
verify( verify(
@ -361,7 +385,9 @@ void main() {
group('sparky', () { group('sparky', () {
test('plays the correct file', () async { test('plays the correct file', () async {
await Future.wait(audioPlayer.load()); await Future.wait(
audioPlayer.load().map((loadableBuilder) => loadableBuilder()),
);
audioPlayer.play(PinballAudio.sparky); audioPlayer.play(PinballAudio.sparky);
verify( verify(
@ -375,7 +401,9 @@ void main() {
group('dino', () { group('dino', () {
test('plays the correct file', () async { test('plays the correct file', () async {
await Future.wait(audioPlayer.load()); await Future.wait(
audioPlayer.load().map((loadableBuilder) => loadableBuilder()),
);
audioPlayer.play(PinballAudio.dino); audioPlayer.play(PinballAudio.dino);
verify( verify(
@ -389,7 +417,9 @@ void main() {
group('android', () { group('android', () {
test('plays the correct file', () async { test('plays the correct file', () async {
await Future.wait(audioPlayer.load()); await Future.wait(
audioPlayer.load().map((loadableBuilder) => loadableBuilder()),
);
audioPlayer.play(PinballAudio.android); audioPlayer.play(PinballAudio.android);
verify( verify(
@ -403,7 +433,9 @@ void main() {
group('dash', () { group('dash', () {
test('plays the correct file', () async { test('plays the correct file', () async {
await Future.wait(audioPlayer.load()); await Future.wait(
audioPlayer.load().map((loadableBuilder) => loadableBuilder()),
);
audioPlayer.play(PinballAudio.dash); audioPlayer.play(PinballAudio.dash);
verify( verify(
@ -417,7 +449,9 @@ void main() {
group('launcher', () { group('launcher', () {
test('plays the correct file', () async { test('plays the correct file', () async {
await Future.wait(audioPlayer.load()); await Future.wait(
audioPlayer.load().map((loadableBuilder) => loadableBuilder()),
);
audioPlayer.play(PinballAudio.launcher); audioPlayer.play(PinballAudio.launcher);
verify( verify(
@ -431,7 +465,9 @@ void main() {
group('rollover', () { group('rollover', () {
test('plays the correct file', () async { test('plays the correct file', () async {
await Future.wait(audioPlayer.load()); await Future.wait(
audioPlayer.load().map((loadableBuilder) => loadableBuilder()),
);
audioPlayer.play(PinballAudio.rollover); audioPlayer.play(PinballAudio.rollover);
verify( verify(
@ -445,7 +481,9 @@ void main() {
group('ioPinballVoiceOver', () { group('ioPinballVoiceOver', () {
test('plays the correct file', () async { test('plays the correct file', () async {
await Future.wait(audioPlayer.load()); await Future.wait(
audioPlayer.load().map((loadableBuilder) => loadableBuilder()),
);
audioPlayer.play(PinballAudio.ioPinballVoiceOver); audioPlayer.play(PinballAudio.ioPinballVoiceOver);
verify( verify(
@ -459,7 +497,9 @@ void main() {
group('gameOverVoiceOver', () { group('gameOverVoiceOver', () {
test('plays the correct file', () async { test('plays the correct file', () async {
await Future.wait(audioPlayer.load()); await Future.wait(
audioPlayer.load().map((loadableBuilder) => loadableBuilder()),
);
audioPlayer.play(PinballAudio.gameOverVoiceOver); audioPlayer.play(PinballAudio.gameOverVoiceOver);
verify( verify(
@ -473,7 +513,9 @@ void main() {
group('backgroundMusic', () { group('backgroundMusic', () {
test('plays the correct file', () async { test('plays the correct file', () async {
await Future.wait(audioPlayer.load()); await Future.wait(
audioPlayer.load().map((loadableBuilder) => loadableBuilder()),
);
audioPlayer.play(PinballAudio.backgroundMusic); audioPlayer.play(PinballAudio.backgroundMusic);
verify( verify(
@ -485,7 +527,9 @@ void main() {
}); });
test('plays only once', () async { test('plays only once', () async {
await Future.wait(audioPlayer.load()); await Future.wait(
audioPlayer.load().map((loadableBuilder) => loadableBuilder()),
);
audioPlayer audioPlayer
..play(PinballAudio.backgroundMusic) ..play(PinballAudio.backgroundMusic)
..play(PinballAudio.backgroundMusic); ..play(PinballAudio.backgroundMusic);
@ -503,7 +547,9 @@ void main() {
'throws assertions error when playing an unregistered audio', 'throws assertions error when playing an unregistered audio',
() async { () async {
audioPlayer.audios.remove(PinballAudio.google); audioPlayer.audios.remove(PinballAudio.google);
await Future.wait(audioPlayer.load()); await Future.wait(
audioPlayer.load().map((loadableBuilder) => loadableBuilder()),
);
expect( expect(
() => audioPlayer.play(PinballAudio.google), () => audioPlayer.play(PinballAudio.google),

@ -37,7 +37,7 @@ void main() {
shareRepository = _MockShareRepository(); shareRepository = _MockShareRepository();
pinballAudioPlayer = _MockPinballAudioPlayer(); pinballAudioPlayer = _MockPinballAudioPlayer();
platformHelper = _MockPlatformHelper(); platformHelper = _MockPlatformHelper();
when(pinballAudioPlayer.load).thenAnswer((_) => [Future.value()]); when(pinballAudioPlayer.load).thenAnswer((_) => [Future.value]);
}); });
testWidgets('renders PinballGamePage', (tester) async { testWidgets('renders PinballGamePage', (tester) async {

@ -7,7 +7,7 @@ void main() {
group('AssetsManagerState', () { group('AssetsManagerState', () {
test('can be instantiated', () { test('can be instantiated', () {
expect( expect(
AssetsManagerState(loadables: const [], loaded: const []), AssetsManagerState(assetsCount: 0, loaded: 0),
isNotNull, isNotNull,
); );
}); });
@ -17,22 +17,19 @@ void main() {
AssetsManagerState.initial(), AssetsManagerState.initial(),
equals( equals(
AssetsManagerState( AssetsManagerState(
loadables: const [], assetsCount: 0,
loaded: const [], loaded: 0,
), ),
), ),
); );
}); });
group('progress', () { group('progress', () {
final future1 = Future<void>.value();
final future2 = Future<void>.value();
test('returns 0 when no future is loaded', () { test('returns 0 when no future is loaded', () {
expect( expect(
AssetsManagerState( AssetsManagerState(
loadables: [future1, future2], assetsCount: 2,
loaded: const [], loaded: 0,
).progress, ).progress,
equals(0), equals(0),
); );
@ -41,8 +38,8 @@ void main() {
test('returns the correct value when some of the futures are loaded', () { test('returns the correct value when some of the futures are loaded', () {
expect( expect(
AssetsManagerState( AssetsManagerState(
loadables: [future1, future2], assetsCount: 2,
loaded: [future1], loaded: 1,
).progress, ).progress,
equals(0.5), equals(0.5),
); );
@ -51,8 +48,8 @@ void main() {
test('returns the 1 when all futures are loaded', () { test('returns the 1 when all futures are loaded', () {
expect( expect(
AssetsManagerState( AssetsManagerState(
loadables: [future1, future2], assetsCount: 2,
loaded: [future1, future2], loaded: 2,
).progress, ).progress,
equals(1), equals(1),
); );
@ -60,18 +57,16 @@ void main() {
}); });
group('copyWith', () { group('copyWith', () {
final future = Future<void>.value(); test('returns a copy with the updated assetsCount', () {
test('returns a copy with the updated loadables', () {
expect( expect(
AssetsManagerState( AssetsManagerState(
loadables: const [], assetsCount: 0,
loaded: const [], loaded: 0,
).copyWith(loadables: [future]), ).copyWith(assetsCount: 1),
equals( equals(
AssetsManagerState( AssetsManagerState(
loadables: [future], assetsCount: 1,
loaded: const [], loaded: 0,
), ),
), ),
); );
@ -80,13 +75,13 @@ void main() {
test('returns a copy with the updated loaded', () { test('returns a copy with the updated loaded', () {
expect( expect(
AssetsManagerState( AssetsManagerState(
loadables: const [], assetsCount: 0,
loaded: const [], loaded: 0,
).copyWith(loaded: [future]), ).copyWith(loaded: 1),
equals( equals(
AssetsManagerState( AssetsManagerState(
loadables: const [], assetsCount: 0,
loaded: [future], loaded: 1,
), ),
), ),
); );
@ -94,47 +89,29 @@ void main() {
}); });
test('supports value comparison', () { test('supports value comparison', () {
final future1 = Future<void>.value();
final future2 = Future<void>.value();
expect(
AssetsManagerState(
loadables: const [],
loaded: const [],
),
equals(
AssetsManagerState(
loadables: const [],
loaded: const [],
),
),
);
expect( expect(
AssetsManagerState( AssetsManagerState(
loadables: [future1], assetsCount: 0,
loaded: const [], loaded: 0,
), ),
isNot(
equals( equals(
AssetsManagerState( AssetsManagerState(
loadables: [future2], assetsCount: 0,
loaded: const [], loaded: 0,
),
), ),
), ),
); );
expect( expect(
AssetsManagerState( AssetsManagerState(
loadables: const [], assetsCount: 1,
loaded: [future1], loaded: 0,
), ),
isNot( isNot(
equals( equals(
AssetsManagerState( AssetsManagerState(
loadables: const [], assetsCount: 1,
loaded: [future2], loaded: 1,
), ),
), ),
), ),

@ -12,9 +12,9 @@ void main() {
late AssetsManagerCubit assetsManagerCubit; late AssetsManagerCubit assetsManagerCubit;
setUp(() { setUp(() {
final initialAssetsState = AssetsManagerState( const initialAssetsState = AssetsManagerState(
loadables: [Future<void>.value()], assetsCount: 1,
loaded: const [], loaded: 0,
); );
assetsManagerCubit = _MockAssetsManagerCubit(); assetsManagerCubit = _MockAssetsManagerCubit();
whenListen( whenListen(

@ -35,7 +35,7 @@ class _TestPinballGame extends PinballGame {
@override @override
Future<void> onLoad() async { Future<void> onLoad() async {
images.prefix = ''; images.prefix = '';
final futures = preLoadAssets(); final futures = preLoadAssets().map((loadableBuilder) => loadableBuilder());
await Future.wait<void>(futures); await Future.wait<void>(futures);
await super.onLoad(); await super.onLoad();
} }
@ -56,7 +56,7 @@ class _TestDebugPinballGame extends DebugPinballGame {
@override @override
Future<void> onLoad() async { Future<void> onLoad() async {
images.prefix = ''; images.prefix = '';
final futures = preLoadAssets(); final futures = preLoadAssets().map((loadableBuilder) => loadableBuilder());
await Future.wait<void>(futures); await Future.wait<void>(futures);
await super.onLoad(); await super.onLoad();
} }
@ -215,7 +215,8 @@ void main() {
'paints sprites with FilterQuality.medium', 'paints sprites with FilterQuality.medium',
setUp: (game, tester) async { setUp: (game, tester) async {
game.images.prefix = ''; game.images.prefix = '';
final futures = game.preLoadAssets(); final futures =
game.preLoadAssets().map((loadableBuilder) => loadableBuilder());
await Future.wait<void>(futures); await Future.wait<void>(futures);
await game.ready(); await game.ready();

@ -37,9 +37,13 @@ class _TestPinballGame extends PinballGame {
images.prefix = ''; images.prefix = '';
final futures = [ final futures = [
...preLoadAssets(), ...preLoadAssets(),
preFetchLeaderboard(), ...BonusAnimation.loadAssets(),
...SelectedCharacter.loadAssets(),
preFetchLeaderboard,
]; ];
await Future.wait<void>(futures); await Future.wait<void>(
futures.map((loadableBuilder) => loadableBuilder()).toList(),
);
return super.onLoad(); return super.onLoad();
} }
@ -78,7 +82,9 @@ void main() {
late GameBloc gameBloc; late GameBloc gameBloc;
setUp(() async { setUp(() async {
await Future.wait<void>(game.preLoadAssets()); await Future.wait<void>(
game.preLoadAssets().map((loadableBuilder) => loadableBuilder()),
);
characterThemeCubit = _MockCharacterThemeCubit(); characterThemeCubit = _MockCharacterThemeCubit();
gameBloc = _MockGameBloc(); gameBloc = _MockGameBloc();
@ -122,8 +128,8 @@ void main() {
(tester) async { (tester) async {
final assetsManagerCubit = _MockAssetsManagerCubit(); final assetsManagerCubit = _MockAssetsManagerCubit();
final initialAssetsState = AssetsManagerState( final initialAssetsState = AssetsManagerState(
loadables: [Future<void>.value()], assetsCount: 1,
loaded: const [], loaded: 0,
); );
whenListen( whenListen(
assetsManagerCubit, assetsManagerCubit,
@ -146,8 +152,8 @@ void main() {
final startGameBloc = _MockStartGameBloc(); final startGameBloc = _MockStartGameBloc();
final loadedAssetsState = AssetsManagerState( final loadedAssetsState = AssetsManagerState(
loadables: [Future<void>.value()], assetsCount: 1,
loaded: [Future<void>.value()], loaded: 1,
); );
whenListen( whenListen(
assetsManagerCubit, assetsManagerCubit,
@ -179,7 +185,9 @@ void main() {
final startGameBloc = _MockStartGameBloc(); final startGameBloc = _MockStartGameBloc();
setUp(() async { setUp(() async {
await Future.wait<void>(game.preLoadAssets()); await Future.wait<void>(
game.preLoadAssets().map((loadableBuilder) => loadableBuilder()),
);
whenListen( whenListen(
gameBloc, gameBloc,

@ -34,15 +34,15 @@ class _MockPlatformHelper extends Mock implements PlatformHelper {}
PinballAudioPlayer _buildDefaultPinballAudioPlayer() { PinballAudioPlayer _buildDefaultPinballAudioPlayer() {
final audioPlayer = _MockPinballAudioPlayer(); final audioPlayer = _MockPinballAudioPlayer();
when(audioPlayer.load).thenAnswer((_) => [Future.value()]); when(audioPlayer.load).thenAnswer((_) => [Future.value]);
return audioPlayer; return audioPlayer;
} }
AssetsManagerCubit _buildDefaultAssetsManagerCubit() { AssetsManagerCubit _buildDefaultAssetsManagerCubit() {
final cubit = _MockAssetsManagerCubit(); final cubit = _MockAssetsManagerCubit();
final state = AssetsManagerState( const state = AssetsManagerState(
loadables: [Future<void>.value()], assetsCount: 1,
loaded: [Future<void>.value()], loaded: 1,
); );
whenListen( whenListen(
cubit, cubit,

Loading…
Cancel
Save