Browse Source
feat(message): 实现语音消息播放功能
feat(message): 实现语音消息播放功能
- 新增语音播放管理器 VoicePlayerManager,支持播放、暂停、停止等操作- 在聊天页面添加返回时停止播放的逻辑 -语音消息组件支持点击播放/暂停,并显示播放状态- 集成 audioplayers 库用于音频播放-优化语音消息 UI,根据播放状态切换图标 - 支持通过消息 ID 唯一标识和控制音频播放 - 添加播放失败和异常处理机制 - 更新依赖配置,引入 audioplayers 插件ios
6 changed files with 316 additions and 96 deletions
Split View
Diff Options
-
96lib/controller/message/voice_player_manager.dart
-
136lib/pages/message/chat_page.dart
-
1lib/widget/message/message_item.dart
-
122lib/widget/message/voice_item.dart
-
56pubspec.lock
-
1pubspec.yaml
@ -0,0 +1,96 @@ |
|||
import 'package:audioplayers/audioplayers.dart'; |
|||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; |
|||
import 'package:get/get.dart'; |
|||
|
|||
/// 语音播放管理器,单例模式,统一管理语音播放 |
|||
class VoicePlayerManager extends GetxController { |
|||
static VoicePlayerManager? _instance; |
|||
static VoicePlayerManager get instance { |
|||
_instance ??= Get.put(VoicePlayerManager()); |
|||
return _instance!; |
|||
} |
|||
|
|||
final AudioPlayer _audioPlayer = AudioPlayer(); |
|||
String? _currentPlayingId; |
|||
final Rx<String?> currentPlayingId = Rx<String?>(null); |
|||
final Rx<PlayerState> playerState = Rx<PlayerState>(PlayerState.stopped); |
|||
|
|||
VoicePlayerManager() { |
|||
// 监听播放状态变化 |
|||
_audioPlayer.onPlayerStateChanged.listen((state) { |
|||
playerState.value = state; |
|||
if (state == PlayerState.completed) { |
|||
// 播放完成,重置状态 |
|||
_currentPlayingId = null; |
|||
currentPlayingId.value = null; |
|||
} |
|||
}); |
|||
} |
|||
|
|||
/// 播放音频 |
|||
/// [audioId] 音频的唯一标识(通常是消息ID) |
|||
/// [filePath] 音频文件路径 |
|||
Future<void> play(String audioId, String filePath) async { |
|||
try { |
|||
// 如果正在播放其他音频,先停止 |
|||
if (_currentPlayingId != null && _currentPlayingId != audioId) { |
|||
await stop(); |
|||
} |
|||
|
|||
// 如果是同一个音频,则暂停/恢复 |
|||
if (_currentPlayingId == audioId) { |
|||
if (playerState.value == PlayerState.playing) { |
|||
await _audioPlayer.pause(); |
|||
} else { |
|||
await _audioPlayer.resume(); |
|||
} |
|||
return; |
|||
} |
|||
// 播放新音频 |
|||
_currentPlayingId = audioId; |
|||
currentPlayingId.value = audioId; |
|||
await _audioPlayer.play(DeviceFileSource(filePath)); |
|||
} catch (e) { |
|||
print('播放音频失败: $e'); |
|||
_currentPlayingId = null; |
|||
currentPlayingId.value = null; |
|||
} |
|||
} |
|||
|
|||
/// 停止播放 |
|||
Future<void> stop() async { |
|||
try { |
|||
await _audioPlayer.stop(); |
|||
_currentPlayingId = null; |
|||
currentPlayingId.value = null; |
|||
} catch (e) { |
|||
print('停止播放失败: $e'); |
|||
} |
|||
} |
|||
|
|||
/// 暂停播放 |
|||
Future<void> pause() async { |
|||
try { |
|||
await _audioPlayer.pause(); |
|||
} catch (e) { |
|||
print('暂停播放失败: $e'); |
|||
} |
|||
} |
|||
|
|||
/// 检查指定音频是否正在播放 |
|||
bool isPlaying(String audioId) { |
|||
return _currentPlayingId == audioId && |
|||
playerState.value == PlayerState.playing; |
|||
} |
|||
|
|||
/// 检查指定音频是否已加载 |
|||
bool isLoaded(String audioId) { |
|||
return _currentPlayingId == audioId; |
|||
} |
|||
|
|||
@override |
|||
void onClose() { |
|||
_audioPlayer.dispose(); |
|||
super.onClose(); |
|||
} |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save