feat(audio): looping per-season background music system
MusicService (looping audioplayers player, independent of SFX) driven by the active season theme's new 'bgm' key; switches track on season change, pauses on app background, all failures swallowed. Separate Music on/off toggle in Settings (persisted, independent of SFX). Season packs carry bgm keys (menu/season_001/ season_002), manifest regenerated. Assets slot assets/audio/bgm/ ready — drop in menu.mp3/season_001.mp3/season_002.mp3 (CC0) and it plays; silent until then. 180 tests green, analyze clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
import 'package:block_seasons/data/save_repository.dart';
|
||||
import 'package:block_seasons/game/models/season.dart';
|
||||
import 'package:block_seasons/state/providers.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
void main() {
|
||||
group('musicEnabled persistence', () {
|
||||
setUp(() => SharedPreferences.setMockInitialValues({}));
|
||||
|
||||
test('defaults true and persists across reopen', () async {
|
||||
final repo = await SaveRepository.open();
|
||||
expect(repo.musicEnabled, isTrue);
|
||||
await repo.setMusicEnabled(false);
|
||||
final reopened = await SaveRepository.open();
|
||||
expect(reopened.musicEnabled, isFalse);
|
||||
});
|
||||
|
||||
test('legacy save without the flag reads as true', () async {
|
||||
SharedPreferences.setMockInitialValues({
|
||||
'save_v1': '{"saveVersion":1,"progress":{},"flags":{"tutorialDone":true}}',
|
||||
});
|
||||
final repo = await SaveRepository.open();
|
||||
expect(repo.musicEnabled, isTrue);
|
||||
});
|
||||
|
||||
test('musicEnabledProvider toggles and persists', () async {
|
||||
final repo = await SaveRepository.open();
|
||||
final c = ProviderContainer(
|
||||
overrides: [saveRepositoryProvider.overrideWithValue(repo)],
|
||||
);
|
||||
addTearDown(c.dispose);
|
||||
expect(c.read(musicEnabledProvider), isTrue);
|
||||
await c.read(musicEnabledProvider.notifier).toggle();
|
||||
expect(c.read(musicEnabledProvider), isFalse);
|
||||
expect(repo.musicEnabled, isFalse);
|
||||
});
|
||||
});
|
||||
|
||||
group('SeasonTheme.bgm', () {
|
||||
test('defaults to menu and round-trips through json', () {
|
||||
expect(const SeasonTheme().bgm, 'menu');
|
||||
final theme = SeasonTheme.fromJson(const {'bgm': 'season_001'});
|
||||
expect(theme.bgm, 'season_001');
|
||||
expect(SeasonTheme.fromJson(theme.toJson()).bgm, 'season_001');
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user