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 2 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
/// the UI paint first, and then we start loading the assets.
await Future<void>.delayed(const Duration(seconds: 1));
final loadables = <Future<void> Function()>[
_game.preFetchLeaderboard,
..._game.preLoadAssets(),
..._audioPlayer.load(),
...BonusAnimation.loadAssets(),
...SelectedCharacter.loadAssets(),
];
emit(
state.copyWith(
loadables: [
_game.preFetchLeaderboard(),
..._game.preLoadAssets(),
..._audioPlayer.load(),
...BonusAnimation.loadAssets(),
...SelectedCharacter.loadAssets(),
],
assetsCount: loadables.length,
),
);
final all = state.loadables.map((loadable) async {
await loadable;
emit(state.copyWith(loaded: [...state.loaded, loadable]));
}).toList();
await Future.wait(all);
late void Function() _triggerLoad;
_triggerLoad = () async {
if (loadables.isEmpty) return;
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';
/// {@template assets_manager_state}
/// State used to load the game assets
/// State used to load the game assets.
/// {@endtemplate}
class AssetsManagerState extends Equatable {
/// {@macro assets_manager_state}
const AssetsManagerState({
required this.loadables,
required this.assetsCount,
required this.loaded,
});
/// {@macro assets_manager_state}
const AssetsManagerState.initial()
: this(loadables: const [], loaded: const []);
const AssetsManagerState.initial() : this(assetsCount: 0, loaded: 0);
/// List of futures to load
final List<Future> loadables;
/// Number of assets to load.
final int assetsCount;
/// List of loaded futures
final List<Future> loaded;
/// Number of already loaded assets.
final int loaded;
/// Returns a value between 0 and 1 to indicate the loading progress
double get progress =>
loadables.isEmpty ? 0 : loaded.length / loadables.length;
/// Returns a value between 0 and 1 to indicate the loading progress.
double get progress => loaded == 0 ? 0 : loaded / assetsCount;
/// 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;
/// Returns a copy of this instance with the given parameters
/// updated
/// updated.
AssetsManagerState copyWith({
List<Future>? loadables,
List<Future>? loaded,
int? assetsCount,
int? loaded,
}) {
return AssetsManagerState(
loadables: loadables ?? this.loadables,
assetsCount: assetsCount ?? this.assetsCount,
loaded: loaded ?? this.loaded,
);
}
@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.
extension PinballGameAssetsX on PinballGame {
/// Returns a list of assets to be loaded
List<Future<Image>> preLoadAssets() {
List<Future<Image> Function()> preLoadAssets() {
const dashTheme = DashTheme();
const sparkyTheme = SparkyTheme();
const androidTheme = AndroidTheme();
const dinoTheme = DinoTheme();
return [
images.load(components.Assets.images.boardBackground.keyName),
images.load(components.Assets.images.ball.flameEffect.keyName),
images.load(components.Assets.images.signpost.inactive.keyName),
images.load(components.Assets.images.signpost.active1.keyName),
images.load(components.Assets.images.signpost.active2.keyName),
images.load(components.Assets.images.signpost.active3.keyName),
images.load(components.Assets.images.flipper.left.keyName),
images.load(components.Assets.images.flipper.right.keyName),
images.load(components.Assets.images.baseboard.left.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.dimmed.keyName),
images.load(components.Assets.images.kicker.right.lit.keyName),
images.load(components.Assets.images.kicker.right.dimmed.keyName),
images.load(components.Assets.images.slingshot.upper.keyName),
images.load(components.Assets.images.slingshot.lower.keyName),
images.load(components.Assets.images.launchRamp.ramp.keyName),
images.load(
components.Assets.images.launchRamp.foregroundRailing.keyName,
),
images.load(
components.Assets.images.launchRamp.backgroundRailing.keyName,
),
images.load(components.Assets.images.dino.bottomWall.keyName),
images.load(components.Assets.images.dino.topWall.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.mouth.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.inactive.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.main.active.keyName),
images.load(components.Assets.images.dash.bumper.main.inactive.keyName),
images.load(components.Assets.images.plunger.plunger.keyName),
images.load(components.Assets.images.plunger.rocket.keyName),
images.load(components.Assets.images.boundary.bottom.keyName),
images.load(components.Assets.images.boundary.outer.keyName),
images.load(components.Assets.images.boundary.outerBottom.keyName),
images.load(components.Assets.images.android.spaceship.saucer.keyName),
images
() => images.load(components.Assets.images.boardBackground.keyName),
() => images.load(components.Assets.images.ball.flameEffect.keyName),
() => images.load(components.Assets.images.signpost.inactive.keyName),
() => images.load(components.Assets.images.signpost.active1.keyName),
() => images.load(components.Assets.images.signpost.active2.keyName),
() => images.load(components.Assets.images.signpost.active3.keyName),
() => images.load(components.Assets.images.flipper.left.keyName),
() => images.load(components.Assets.images.flipper.right.keyName),
() => images.load(components.Assets.images.baseboard.left.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.dimmed.keyName),
() => images.load(components.Assets.images.kicker.right.lit.keyName),
() => images.load(components.Assets.images.kicker.right.dimmed.keyName),
() => images.load(components.Assets.images.slingshot.upper.keyName),
() => images.load(components.Assets.images.slingshot.lower.keyName),
() => images.load(components.Assets.images.launchRamp.ramp.keyName),
() => images.load(
components.Assets.images.launchRamp.foregroundRailing.keyName,
),
() => images.load(
components.Assets.images.launchRamp.backgroundRailing.keyName,
),
() => images.load(components.Assets.images.dino.bottomWall.keyName),
() => images.load(components.Assets.images.dino.topWall.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.mouth.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.inactive.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.main.active.keyName),
() => images
.load(components.Assets.images.dash.bumper.main.inactive.keyName),
() => images.load(components.Assets.images.plunger.plunger.keyName),
() => images.load(components.Assets.images.plunger.rocket.keyName),
() => images.load(components.Assets.images.boundary.bottom.keyName),
() => images.load(components.Assets.images.boundary.outer.keyName),
() => images.load(components.Assets.images.boundary.outerBottom.keyName),
() => images
.load(components.Assets.images.android.spaceship.saucer.keyName),
() => images
.load(components.Assets.images.android.spaceship.animatronic.keyName),
images.load(components.Assets.images.android.spaceship.lightBeam.keyName),
images.load(components.Assets.images.android.ramp.boardOpening.keyName),
images.load(
components.Assets.images.android.ramp.railingForeground.keyName,
),
images.load(
components.Assets.images.android.ramp.railingBackground.keyName,
),
images.load(components.Assets.images.android.ramp.main.keyName),
images.load(components.Assets.images.android.ramp.arrow.inactive.keyName),
images.load(
components.Assets.images.android.ramp.arrow.active1.keyName,
),
images.load(
components.Assets.images.android.ramp.arrow.active2.keyName,
),
images.load(
components.Assets.images.android.ramp.arrow.active3.keyName,
),
images.load(
components.Assets.images.android.ramp.arrow.active4.keyName,
),
images.load(
components.Assets.images.android.ramp.arrow.active5.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.bumper.a.lit.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.dimmed.keyName),
images.load(components.Assets.images.android.bumper.cow.lit.keyName),
images.load(components.Assets.images.android.bumper.cow.dimmed.keyName),
images.load(components.Assets.images.sparky.computer.top.keyName),
images.load(components.Assets.images.sparky.computer.base.keyName),
images.load(components.Assets.images.sparky.computer.glow.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.b.lit.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.dimmed.keyName),
images.load(components.Assets.images.backbox.marquee.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.twitter.keyName),
images.load(
components.Assets.images.backbox.displayTitleDecoration.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.letter2.lit.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.dimmed.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.letter5.lit.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.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.right.decal.keyName),
images.load(components.Assets.images.googleRollover.right.pin.keyName),
images.load(components.Assets.images.multiball.lit.keyName),
images.load(components.Assets.images.multiball.dimmed.keyName),
images.load(components.Assets.images.multiplier.x2.lit.keyName),
images.load(components.Assets.images.multiplier.x2.dimmed.keyName),
images.load(components.Assets.images.multiplier.x3.lit.keyName),
images.load(components.Assets.images.multiplier.x3.dimmed.keyName),
images.load(components.Assets.images.multiplier.x4.lit.keyName),
images.load(components.Assets.images.multiplier.x4.dimmed.keyName),
images.load(components.Assets.images.multiplier.x5.lit.keyName),
images.load(components.Assets.images.multiplier.x5.dimmed.keyName),
images.load(components.Assets.images.multiplier.x6.lit.keyName),
images.load(components.Assets.images.multiplier.x6.dimmed.keyName),
images.load(components.Assets.images.score.fiveThousand.keyName),
images.load(components.Assets.images.score.twentyThousand.keyName),
images.load(components.Assets.images.score.twoHundredThousand.keyName),
images.load(components.Assets.images.score.oneMillion.keyName),
images.load(components.Assets.images.flapper.backSupport.keyName),
images.load(components.Assets.images.flapper.frontSupport.keyName),
images.load(components.Assets.images.flapper.flap.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.arrowRight.keyName),
images.load(androidTheme.leaderboardIcon.keyName),
images.load(androidTheme.ball.keyName),
images.load(dashTheme.leaderboardIcon.keyName),
images.load(dashTheme.ball.keyName),
images.load(dinoTheme.leaderboardIcon.keyName),
images.load(dinoTheme.ball.keyName),
images.load(sparkyTheme.leaderboardIcon.keyName),
images.load(sparkyTheme.ball.keyName),
images.load(androidTheme.background.keyName),
images.load(dashTheme.background.keyName),
images.load(dinoTheme.background.keyName),
images.load(sparkyTheme.background.keyName),
() => images
.load(components.Assets.images.android.spaceship.lightBeam.keyName),
() => images
.load(components.Assets.images.android.ramp.boardOpening.keyName),
() => images.load(
components.Assets.images.android.ramp.railingForeground.keyName,
),
() => images.load(
components.Assets.images.android.ramp.railingBackground.keyName,
),
() => images.load(components.Assets.images.android.ramp.main.keyName),
() => images
.load(components.Assets.images.android.ramp.arrow.inactive.keyName),
() => images.load(
components.Assets.images.android.ramp.arrow.active1.keyName,
),
() => images.load(
components.Assets.images.android.ramp.arrow.active2.keyName,
),
() => images.load(
components.Assets.images.android.ramp.arrow.active3.keyName,
),
() => images.load(
components.Assets.images.android.ramp.arrow.active4.keyName,
),
() => images.load(
components.Assets.images.android.ramp.arrow.active5.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.bumper.a.lit.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.dimmed.keyName),
() =>
images.load(components.Assets.images.android.bumper.cow.lit.keyName),
() => images
.load(components.Assets.images.android.bumper.cow.dimmed.keyName),
() => images.load(components.Assets.images.sparky.computer.top.keyName),
() => images.load(components.Assets.images.sparky.computer.base.keyName),
() => images.load(components.Assets.images.sparky.computer.glow.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.b.lit.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.dimmed.keyName),
() => images.load(components.Assets.images.backbox.marquee.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.twitter.keyName),
() => images.load(
components.Assets.images.backbox.displayTitleDecoration.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.letter2.lit.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.dimmed.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.letter5.lit.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.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.right.decal.keyName),
() => images
.load(components.Assets.images.googleRollover.right.pin.keyName),
() => images.load(components.Assets.images.multiball.lit.keyName),
() => images.load(components.Assets.images.multiball.dimmed.keyName),
() => images.load(components.Assets.images.multiplier.x2.lit.keyName),
() => images.load(components.Assets.images.multiplier.x2.dimmed.keyName),
() => images.load(components.Assets.images.multiplier.x3.lit.keyName),
() => images.load(components.Assets.images.multiplier.x3.dimmed.keyName),
() => images.load(components.Assets.images.multiplier.x4.lit.keyName),
() => images.load(components.Assets.images.multiplier.x4.dimmed.keyName),
() => images.load(components.Assets.images.multiplier.x5.lit.keyName),
() => images.load(components.Assets.images.multiplier.x5.dimmed.keyName),
() => images.load(components.Assets.images.multiplier.x6.lit.keyName),
() => images.load(components.Assets.images.multiplier.x6.dimmed.keyName),
() => images.load(components.Assets.images.score.fiveThousand.keyName),
() => images.load(components.Assets.images.score.twentyThousand.keyName),
() => images
.load(components.Assets.images.score.twoHundredThousand.keyName),
() => images.load(components.Assets.images.score.oneMillion.keyName),
() => images.load(components.Assets.images.flapper.backSupport.keyName),
() => images.load(components.Assets.images.flapper.frontSupport.keyName),
() => images.load(components.Assets.images.flapper.flap.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.arrowRight.keyName),
() => images.load(androidTheme.leaderboardIcon.keyName),
() => images.load(androidTheme.ball.keyName),
() => images.load(dashTheme.leaderboardIcon.keyName),
() => images.load(dashTheme.ball.keyName),
() => images.load(dinoTheme.leaderboardIcon.keyName),
() => images.load(dinoTheme.ball.keyName),
() => images.load(sparkyTheme.leaderboardIcon.keyName),
() => images.load(sparkyTheme.ball.keyName),
() => images.load(androidTheme.background.keyName),
() => images.load(dashTheme.background.keyName),
() => images.load(dinoTheme.background.keyName),
() => images.load(sparkyTheme.background.keyName),
];
}
}

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

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

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

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

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

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

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

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

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

Loading…
Cancel
Save