110 lines
3.5 KiB
Dart
110 lines
3.5 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:audioplayers/audioplayers.dart';
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
import '../models/prank_sound.dart';
|
|
|
|
class SoundManager {
|
|
static final SoundManager _instance = SoundManager._internal();
|
|
factory SoundManager() => _instance;
|
|
SoundManager._internal();
|
|
|
|
final AudioPlayer audioPlayer = AudioPlayer();
|
|
|
|
// 播放状态 Notifiers
|
|
final ValueNotifier<PrankSound?> currentSoundNotifier = ValueNotifier(null);
|
|
final ValueNotifier<bool> isPlayingNotifier = ValueNotifier(false);
|
|
final ValueNotifier<Duration> positionNotifier = ValueNotifier(Duration.zero);
|
|
final ValueNotifier<Duration> durationNotifier = ValueNotifier(Duration.zero);
|
|
|
|
// 设置状态 Notifiers (支持 UI 监听)
|
|
final ValueNotifier<double> volumeNotifier = ValueNotifier(1.0); // 默认 100%
|
|
final ValueNotifier<bool> loopNotifier = ValueNotifier(false); // 默认不循环
|
|
|
|
static const String KEY_VOLUME = 'app_volume';
|
|
static const String KEY_LOOP = 'app_loop';
|
|
|
|
Future<void> init() async {
|
|
// 监听播放器事件
|
|
audioPlayer.onPlayerStateChanged.listen((state) {
|
|
isPlayingNotifier.value = state == PlayerState.playing;
|
|
});
|
|
|
|
audioPlayer.onDurationChanged.listen((d) {
|
|
durationNotifier.value = d;
|
|
});
|
|
|
|
audioPlayer.onPositionChanged.listen((p) {
|
|
positionNotifier.value = p;
|
|
});
|
|
|
|
audioPlayer.onPlayerComplete.listen((_) {
|
|
// 只有在非循环模式下,播放结束才停止
|
|
if (!loopNotifier.value) {
|
|
isPlayingNotifier.value = false;
|
|
positionNotifier.value = Duration.zero;
|
|
}
|
|
});
|
|
|
|
// 加载本地设置
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final double savedVolume = prefs.getDouble(KEY_VOLUME) ?? 1.0;
|
|
final bool savedLoop = prefs.getBool(KEY_LOOP) ?? false;
|
|
|
|
// 更新内存状态
|
|
volumeNotifier.value = savedVolume;
|
|
loopNotifier.value = savedLoop;
|
|
|
|
// 应用到播放器
|
|
await audioPlayer.setVolume(savedVolume);
|
|
await audioPlayer.setReleaseMode(savedLoop ? ReleaseMode.loop : ReleaseMode.stop);
|
|
}
|
|
|
|
// 设置音量并保存
|
|
Future<void> setVolume(double volume) async {
|
|
volumeNotifier.value = volume;
|
|
await audioPlayer.setVolume(volume);
|
|
final prefs = await SharedPreferences.getInstance();
|
|
await prefs.setDouble(KEY_VOLUME, volume);
|
|
}
|
|
|
|
// 设置循环并保存
|
|
Future<void> setLooping(bool loop) async {
|
|
loopNotifier.value = loop;
|
|
await audioPlayer.setReleaseMode(loop ? ReleaseMode.loop : ReleaseMode.stop);
|
|
final prefs = await SharedPreferences.getInstance();
|
|
await prefs.setBool(KEY_LOOP, loop);
|
|
}
|
|
|
|
Future<void> play(PrankSound sound) async {
|
|
try {
|
|
if (currentSoundNotifier.value == sound) {
|
|
if (isPlayingNotifier.value) {
|
|
await audioPlayer.pause();
|
|
} else {
|
|
await audioPlayer.resume();
|
|
}
|
|
} else {
|
|
await audioPlayer.stop();
|
|
currentSoundNotifier.value = sound;
|
|
|
|
// 播放前确保应用了当前的设置
|
|
await audioPlayer.setVolume(volumeNotifier.value);
|
|
await audioPlayer.setReleaseMode(loopNotifier.value ? ReleaseMode.loop : ReleaseMode.stop);
|
|
|
|
if (sound.mp3Url.isNotEmpty) {
|
|
await audioPlayer.play(UrlSource(sound.mp3Url));
|
|
}
|
|
}
|
|
} catch (e) {
|
|
debugPrint("Play Error: $e");
|
|
}
|
|
}
|
|
|
|
Future<void> stop() async {
|
|
await audioPlayer.stop();
|
|
currentSoundNotifier.value = null;
|
|
isPlayingNotifier.value = false;
|
|
positionNotifier.value = Duration.zero;
|
|
}
|
|
}
|