353 lines
10 KiB
Dart
353 lines
10 KiB
Dart
import 'dart:async';
|
|
import 'dart:convert';
|
|
import 'dart:math';
|
|
|
|
import 'package:agora_rtc_engine/agora_rtc_engine.dart';
|
|
import 'package:flutter/cupertino.dart';
|
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
|
import 'package:aslan/chatvibe_managers/rtc_manager.dart';
|
|
import 'package:on_audio_query/on_audio_query.dart';
|
|
import 'package:provider/provider.dart';
|
|
|
|
import 'package:aslan/chatvibe_ui/components/at_tts.dart';
|
|
import 'package:aslan/chatvibe_data/sources/local/data_persistence.dart';
|
|
import 'package:aslan/chatvibe_data/models/at_music_mode.dart';
|
|
|
|
import '../chatvibe_features/room/music/control/at_room_music_control_page.dart';
|
|
|
|
typedef MixingCurrentPositionChange = Function(int currentValue, int maxValue);
|
|
|
|
class AudioManager with ChangeNotifier {
|
|
ATMusicMode? currentMusicMode;
|
|
int playingIndex = -1;
|
|
List<SongModel> localSongs = [];
|
|
List<ATMusicMode> addedSongs = [];
|
|
Map<String, ATMusicMode> addedMusicMap = {};
|
|
AudioMixingStateType state = AudioMixingStateType.audioMixingStateStopped;
|
|
int playModel = 0;
|
|
OnAudioQuery? _audioQuery;
|
|
Timer? _timer;
|
|
|
|
MixingCurrentPositionChange? changeCall;
|
|
|
|
|
|
void startMixingCurrentPositionTimer(BuildContext context) {
|
|
_timer?.cancel();
|
|
_timer = Timer.periodic(Duration(milliseconds: 550), (timer) async {
|
|
int currentPos =
|
|
await Provider.of<RealTimeCommunicationManager>(
|
|
context,
|
|
listen: false,
|
|
).engine!.getAudioMixingCurrentPosition();
|
|
// 获取音乐总时长
|
|
int duration =
|
|
await Provider.of<RealTimeCommunicationManager>(
|
|
context,
|
|
listen: false,
|
|
).engine!.getAudioMixingDuration();
|
|
changeCall?.call(currentPos, duration);
|
|
if (currentPos == duration) {
|
|
if (currentPos > 0) {
|
|
playFinished(context);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
void stopTimer() {
|
|
_timer?.cancel();
|
|
}
|
|
|
|
Future getAtSongs() async {
|
|
try {
|
|
localSongs.clear();
|
|
_audioQuery ??= OnAudioQuery();
|
|
// 检查并请求存储权限
|
|
bool hasPermission = await _audioQuery!.checkAndRequest();
|
|
// 确保权限已授予后再进行查询
|
|
if (hasPermission) {
|
|
// 查询设备上的所有歌曲
|
|
var ss = await _audioQuery!.querySongs();
|
|
for (var s in ss) {
|
|
if ((s.duration ?? 0) > 10000) {
|
|
localSongs.add(s);
|
|
}
|
|
}
|
|
loadAtRoomMusics();
|
|
} else {
|
|
// 用户拒绝了权限,需要进行处理(例如显示提示)
|
|
ATTts.show("Failed to obtain permission");
|
|
return [];
|
|
}
|
|
} catch (e) {}
|
|
}
|
|
|
|
void addRoomMusic(ATMusicMode music) {
|
|
try {
|
|
List<ATMusicMode> musics = [];
|
|
String musicJson = DataPersistence.getUserRoomMusic();
|
|
if (musicJson.isNotEmpty) {
|
|
musics =
|
|
(jsonDecode(musicJson) as List)
|
|
.map((e) => ATMusicMode.fromJson(e))
|
|
.toList();
|
|
}
|
|
bool isHas = false;
|
|
if (musics.isNotEmpty) {
|
|
for (var m in musics) {
|
|
if (m.title == music.title) {
|
|
isHas = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!isHas) {
|
|
musics.add(music);
|
|
}
|
|
String newMusicJson = jsonEncode(musics.map((v) => v.toJson()).toList());
|
|
DataPersistence.setUserRoomMusic(newMusicJson);
|
|
addedMusicMap[music.title ?? ""] = music;
|
|
notifyListeners();
|
|
} catch (e) {}
|
|
}
|
|
|
|
void deleteRoomMusic(BuildContext context, ATMusicMode music) {
|
|
try {
|
|
addedMusicMap.remove(music.title);
|
|
List<ATMusicMode> musics = [];
|
|
String musicJson = DataPersistence.getUserRoomMusic();
|
|
if (musicJson.isNotEmpty) {
|
|
musics =
|
|
(jsonDecode(musicJson) as List)
|
|
.map((e) => ATMusicMode.fromJson(e))
|
|
.toList();
|
|
}
|
|
if (musics.isNotEmpty) {
|
|
musics.removeWhere((m) => m.title == music.title);
|
|
}
|
|
String newMusicJson = jsonEncode(musics.map((v) => v.toJson()).toList());
|
|
DataPersistence.setUserRoomMusic(newMusicJson);
|
|
if (music.title == currentMusicMode?.title) {
|
|
currentMusicMode = null;
|
|
Provider.of<RealTimeCommunicationManager>(context, listen: false).stopMusic();
|
|
SmartDialog.dismiss(tag: "showRoomMusicControl");
|
|
reset();
|
|
}
|
|
} catch (e) {}
|
|
notifyListeners();
|
|
}
|
|
|
|
void loadAtRoomMusics() {
|
|
try {
|
|
addedSongs.clear();
|
|
String musicJson = DataPersistence.getUserRoomMusic();
|
|
if (musicJson.isNotEmpty) {
|
|
addedSongs =
|
|
(jsonDecode(musicJson) as List)
|
|
.map((e) => ATMusicMode.fromJson(e))
|
|
.toList();
|
|
}
|
|
} catch (e) {}
|
|
if (addedSongs.isNotEmpty) {
|
|
addedMusicMap = {for (var music in addedSongs) music.title ?? "": music};
|
|
}
|
|
notifyListeners();
|
|
}
|
|
|
|
void playMusic(BuildContext context, ATMusicMode music, int playingIndex) {
|
|
if (this.playingIndex == playingIndex) {
|
|
SmartDialog.show(
|
|
tag: "showRoomMusicControl",
|
|
alignment: Alignment.center,
|
|
debounce: true,
|
|
animationType: SmartAnimationType.fade,
|
|
clickMaskDismiss: true,
|
|
builder: (_) {
|
|
return ATRoomMusicControlPage();
|
|
},
|
|
);
|
|
return;
|
|
}
|
|
currentMusicMode = music;
|
|
this.playingIndex = playingIndex;
|
|
Provider.of<RealTimeCommunicationManager>(
|
|
context,
|
|
listen: false,
|
|
).playMusic(music.localPath ?? "", playModel == 0 ? -1 : 1);
|
|
notifyListeners();
|
|
SmartDialog.dismiss(tag: "showRoomMusic");
|
|
SmartDialog.show(
|
|
tag: "showRoomMusicControl",
|
|
alignment: Alignment.center,
|
|
debounce: true,
|
|
animationType: SmartAnimationType.fade,
|
|
clickMaskDismiss: true,
|
|
builder: (_) {
|
|
return ATRoomMusicControlPage();
|
|
},
|
|
);
|
|
}
|
|
|
|
void setPlayState(AudioMixingStateType state, BuildContext context) {
|
|
if (state == AudioMixingStateType.audioMixingStatePlaying) {
|
|
startMixingCurrentPositionTimer(context);
|
|
}
|
|
this.state = state;
|
|
notifyListeners();
|
|
}
|
|
|
|
void reset() {
|
|
playingIndex = -1;
|
|
playModel = 0;
|
|
currentMusicMode = null;
|
|
state = AudioMixingStateType.audioMixingStateStopped;
|
|
stopTimer();
|
|
notifyListeners();
|
|
}
|
|
|
|
///暂停或者播放
|
|
void playOrPause(BuildContext context) {
|
|
if (state == AudioMixingStateType.audioMixingStatePlaying) {
|
|
Provider.of<RealTimeCommunicationManager>(context, listen: false).pauseMusic();
|
|
} else if (state == AudioMixingStateType.audioMixingStatePaused) {
|
|
Provider.of<RealTimeCommunicationManager>(context, listen: false).resumeMusic();
|
|
} else {
|
|
if (currentMusicMode != null) {
|
|
Provider.of<RealTimeCommunicationManager>(
|
|
context,
|
|
listen: false,
|
|
).playMusic(currentMusicMode!.localPath ?? "", playModel == 0 ? -1 : 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
void switchModel() {
|
|
if (playModel == 0) {
|
|
playModel = 1;
|
|
} else if (playModel == 1) {
|
|
playModel = 2;
|
|
} else {
|
|
playModel = 0;
|
|
}
|
|
notifyListeners();
|
|
}
|
|
|
|
///上一首
|
|
void previous(BuildContext context) {
|
|
if (playingIndex == 0) {
|
|
return;
|
|
} else {
|
|
playingIndex = playingIndex - 1;
|
|
currentMusicMode = addedSongs[playingIndex];
|
|
Provider.of<RealTimeCommunicationManager>(
|
|
context,
|
|
listen: false,
|
|
).playMusic(currentMusicMode?.localPath ?? "", playModel == 0 ? -1 : 1);
|
|
notifyListeners();
|
|
}
|
|
}
|
|
|
|
///下一首
|
|
void playNext(BuildContext context) {
|
|
if (playingIndex == addedSongs.length - 1) {
|
|
return;
|
|
} else {
|
|
playingIndex = playingIndex + 1;
|
|
currentMusicMode = addedSongs[playingIndex];
|
|
Provider.of<RealTimeCommunicationManager>(
|
|
context,
|
|
listen: false,
|
|
).playMusic(currentMusicMode?.localPath ?? "", playModel == 0 ? -1 : 1);
|
|
notifyListeners();
|
|
}
|
|
}
|
|
|
|
///随机播放一首
|
|
void playRandom(BuildContext context) {
|
|
playingIndex = Random().nextInt(addedSongs.length + 1);
|
|
currentMusicMode = addedSongs[playingIndex];
|
|
Provider.of<RealTimeCommunicationManager>(
|
|
context,
|
|
listen: false,
|
|
).playMusic(currentMusicMode?.localPath ?? "", playModel == 0 ? -1 : 1);
|
|
notifyListeners();
|
|
}
|
|
|
|
int sTime = 0;
|
|
|
|
///音乐播放完成
|
|
void playFinished(BuildContext context) {
|
|
int nTime = DateTime.now().millisecondsSinceEpoch;
|
|
if (nTime - sTime > 2000) {
|
|
sTime = nTime;
|
|
if (playModel == 1) {
|
|
playRandom(context);
|
|
} else {
|
|
if (playingIndex == addedSongs.length - 1) {
|
|
playingIndex = -1;
|
|
}
|
|
playNext(context);
|
|
}
|
|
}
|
|
}
|
|
|
|
///置顶
|
|
void toUp(ATMusicMode s, int i) {
|
|
if (addedSongs.contains(s)) {
|
|
addedSongs.remove(s);
|
|
addedSongs.insert(0, s);
|
|
}
|
|
int index = 0;
|
|
for (var ms in addedSongs) {
|
|
if (currentMusicMode?.title == ms.title) {
|
|
playingIndex = index;
|
|
break;
|
|
}
|
|
index = index + 1;
|
|
}
|
|
|
|
String newMusicJson = jsonEncode(
|
|
addedSongs.map((v) => v.toJson()).toList(),
|
|
);
|
|
DataPersistence.setUserRoomMusic(newMusicJson);
|
|
notifyListeners();
|
|
}
|
|
|
|
void selectAll() {
|
|
try {
|
|
Future(() {
|
|
List<ATMusicMode> musics = [];
|
|
String musicJson = DataPersistence.getUserRoomMusic();
|
|
if (musicJson.isNotEmpty) {
|
|
musics =
|
|
(jsonDecode(musicJson) as List)
|
|
.map((e) => ATMusicMode.fromJson(e))
|
|
.toList();
|
|
}
|
|
|
|
List<SongModel> result =
|
|
localSongs
|
|
.where((p1) => musics.any((p2) => p2.title == p1.title))
|
|
.toList();
|
|
for (var song in localSongs) {
|
|
if (!result.contains(song)) {
|
|
var mode = ATMusicMode(
|
|
title: song.title,
|
|
artist: song.artist,
|
|
duration: song.duration,
|
|
localPath: song.uri,
|
|
);
|
|
musics.add(mode);
|
|
addedMusicMap[song.title] = mode;
|
|
}
|
|
}
|
|
String newMusicJson = jsonEncode(
|
|
musics.map((v) => v.toJson()).toList(),
|
|
);
|
|
DataPersistence.setUserRoomMusic(newMusicJson);
|
|
notifyListeners();
|
|
});
|
|
} catch (e) {}
|
|
}
|
|
}
|