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,19 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import 'providers.dart';
|
||||
|
||||
/// Background-music on/off, seeded from the save repository. Independent of the
|
||||
/// SFX/haptics ([soundEnabledProvider]) so players can keep one without the
|
||||
/// other — the common "I want sound effects but no music" case.
|
||||
class MusicEnabledNotifier extends Notifier<bool> {
|
||||
@override
|
||||
bool build() => ref.read(saveRepositoryProvider).musicEnabled;
|
||||
|
||||
Future<void> toggle() => set(!state);
|
||||
|
||||
Future<void> set(bool value) async {
|
||||
if (state == value) return;
|
||||
await ref.read(saveRepositoryProvider).setMusicEnabled(value);
|
||||
state = value;
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,10 @@ import '../services/analytics_service.dart';
|
||||
import '../services/audio_service.dart';
|
||||
import '../services/consent_service.dart';
|
||||
import '../services/iap_service.dart';
|
||||
import '../services/music_service.dart';
|
||||
import 'ads_notifier.dart';
|
||||
import 'endless_best_notifier.dart';
|
||||
import 'music_notifier.dart';
|
||||
import 'sound_notifier.dart';
|
||||
import 'game_session_notifier.dart';
|
||||
import 'progress_notifier.dart';
|
||||
@@ -33,6 +35,16 @@ final audioServiceProvider = Provider<AudioService>((ref) {
|
||||
return service;
|
||||
});
|
||||
|
||||
final musicEnabledProvider =
|
||||
NotifierProvider<MusicEnabledNotifier, bool>(MusicEnabledNotifier.new);
|
||||
|
||||
final musicServiceProvider = Provider<MusicService>((ref) {
|
||||
final service = MusicService(enabled: ref.read(musicEnabledProvider));
|
||||
ref.listen<bool>(musicEnabledProvider, (_, next) => service.enabled = next);
|
||||
ref.onDispose(service.dispose);
|
||||
return service;
|
||||
});
|
||||
|
||||
/// Overridden with the opened repository in main() (and in tests).
|
||||
final saveRepositoryProvider = Provider<SaveRepository>(
|
||||
(ref) => throw UnimplementedError('override with an opened SaveRepository'),
|
||||
|
||||
Reference in New Issue
Block a user