Browse Source

上传qq音乐代码优化

newdev_shunjiawei
liwei1dao 1 year ago
parent
commit
7c394dd8fa
  1. 36
      lib/data/services/qq_musoc.dart
  2. 2
      lib/modules/agent/controllers/agent_controller.dart
  3. 19
      lib/modules/agent/views/message_bubble.dart
  4. 67
      lib/modules/agent/views/qqmusic_card.dart
  5. 239
      lib/modules/qqmusic/controllers/qqmusic_playlist_controller.dart
  6. 61
      lib/modules/qqmusic/views/qqmusic_playlist_view.dart

36
lib/data/services/qq_musoc.dart

@ -16,8 +16,8 @@ class QqMusocService extends GetxService {
final currentPosition = 0.obs; // 毫秒 final currentPosition = 0.obs; // 毫秒
final totalDuration = 0.obs; // 毫秒 final totalDuration = 0.obs; // 毫秒
final currentSong = Rxn<SongModel>(); final currentSong = Rxn<SongModel>();
final playlist = <SongModel>[].obs; // final playlist = <SongModel>[].obs;
final currentIndex = 0.obs; // final currentIndex = 0.obs;
// 状态监听定时器 // 状态监听定时器
Timer? _stateMonitorTimer; Timer? _stateMonitorTimer;
@ -259,12 +259,6 @@ class QqMusocService extends GetxService {
); );
if (result['success'] == true) { if (result['success'] == true) {
// 更新全局状态
if (songList != null) {
playlist.assignAll(songList);
currentIndex.value = index;
}
if (currentSongModel != null) { if (currentSongModel != null) {
currentSong.value = currentSongModel; currentSong.value = currentSongModel;
totalDuration.value = currentSongModel.duration; totalDuration.value = currentSongModel.duration;
@ -274,8 +268,8 @@ class QqMusocService extends GetxService {
currentPosition.value = 0; currentPosition.value = 0;
// 启动全局状态监听 // 启动全局状态监听
print('🎵 [QQMusicService] 开始播放,启动全局状态监听'); // print('🎵 [QQMusicService] 开始播放,启动全局状态监听');
startPlaybackStateMonitor(); syncCurrentPlayInfo();
_notifyListeners(); _notifyListeners();
} }
@ -352,10 +346,10 @@ class QqMusocService extends GetxService {
final result = await _qqMusic.skipToNext(); final result = await _qqMusic.skipToNext();
if (result['success'] == true) { if (result['success'] == true) {
// 更新当前索引 // 更新当前索引
if (currentIndex.value < playlist.length - 1) { // if (currentIndex.value < playlist.length - 1) {
currentIndex.value++; // currentIndex.value++;
currentSong.value = playlist[currentIndex.value]; // currentSong.value = playlist[currentIndex.value];
} // }
_notifyListeners(); _notifyListeners();
} }
return result; return result;
@ -370,10 +364,10 @@ class QqMusocService extends GetxService {
final result = await _qqMusic.skipToPrevious(); final result = await _qqMusic.skipToPrevious();
if (result['success'] == true) { if (result['success'] == true) {
// 更新当前索引 // 更新当前索引
if (currentIndex.value > 0) { // if (currentIndex.value > 0) {
currentIndex.value--; // currentIndex.value--;
currentSong.value = playlist[currentIndex.value]; // currentSong.value = playlist[currentIndex.value];
} // }
_notifyListeners(); _notifyListeners();
} }
return result; return result;
@ -415,6 +409,7 @@ class QqMusocService extends GetxService {
/// 同步当前播放信息 - 统一接口 /// 同步当前播放信息 - 统一接口
Future<Map<String, dynamic>> syncCurrentPlayInfo() async { Future<Map<String, dynamic>> syncCurrentPlayInfo() async {
try { try {
_stateMonitorTimer?.cancel(); //先关闭计时器
final result = await _qqMusic.syncCurrentPlayInfo(); final result = await _qqMusic.syncCurrentPlayInfo();
// 如果同步成功,更新全局状态 // 如果同步成功,更新全局状态
@ -457,7 +452,10 @@ class QqMusocService extends GetxService {
currentSong.value = newSong; currentSong.value = newSong;
} }
} }
if (newIsPlaying) {
//正在播放
startPlaybackStateMonitor();
}
// 通知所有监听器 // 通知所有监听器
_notifyListeners(); _notifyListeners();
} }

2
lib/modules/agent/controllers/agent_controller.dart

@ -159,7 +159,7 @@ class AgentController extends GetxController {
startVoiceInput(); //开启语音输入 startVoiceInput(); //开启语音输入
_qqmusicManager.syncCurrentPlayInfo(); // _qqmusicManager.syncCurrentPlayInfo();
} }
// 初始化音乐播放状态 // 初始化音乐播放状态

19
lib/modules/agent/views/message_bubble.dart

@ -1,8 +1,9 @@
import 'package:voitrans/core/utils/logger.dart';
import 'package:voitrans/modules/agent/views/qqmusic_card.dart'; import 'package:voitrans/modules/agent/views/qqmusic_card.dart';
import '../../../data/models/song_model.dart';
import '../../../modules/agent/views/navigation_card.dart'; import '../../../modules/agent/views/navigation_card.dart';
import 'weather_card.dart'; import 'weather_card.dart';
import 'music_card.dart';
import 'travel_card.dart'; import 'travel_card.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
@ -258,10 +259,20 @@ class MessageBubble extends GetView<AgentController> {
if (data != null && data is List) { if (data != null && data is List) {
//qq音乐 //qq音乐
final rawList = data as List? ?? []; final rawList = data as List? ?? [];
final playlist = final songList = rawList
rawList.map((e) => Map<String, dynamic>.from(e)).toList(); .map((item) {
try {
return SongModel.fromJson(item);
} catch (e) {
Logger.e('QQMusicPlaylist', '解析歌曲数据失败: $e, 数据: $item');
return null;
}
})
.where((song) => song != null)
.cast<SongModel>()
.toList();
//音乐播放列表 //音乐播放列表
return buildQQMusicContent(context, playlist); return buildQQMusicContent(context, songList);
} }
} else if (meta!.keys.contains('maps_weather')) { } else if (meta!.keys.contains('maps_weather')) {
final maps_weather = meta!['maps_weather'] as Map<String, dynamic>; final maps_weather = meta!['maps_weather'] as Map<String, dynamic>;

67
lib/modules/agent/views/qqmusic_card.dart

@ -8,20 +8,10 @@ import 'circular_progress_button.dart';
/// 构建音乐项目 /// 构建音乐项目
Widget buildQQMusicItem( Widget buildQQMusicItem(
BuildContext context, String id, String name, String singer, String image) { BuildContext context, List<SongModel> songs, SongModel song, int index) {
final qqMusicService = QqMusocService.to; // 使用QQ音乐全局服务 final qqMusicService = QqMusocService.to; // 使用QQ音乐全局服务
final isDarkMode = Theme.of(context).brightness == Brightness.dark; final isDarkMode = Theme.of(context).brightness == Brightness.dark;
// 创建SongModel对象 - 修复字段名
final song = SongModel(
mid: id,
name: name,
artist: singer, // 修复:使用 artist 而不是 singer
album: '', // 添加必需的 album 字段
duration: 0, // 默认时长,实际播放时会更新
albumPic: image, // 修复:使用 albumPic 而不是 pic
);
return Container( return Container(
padding: EdgeInsets.all(14.w), padding: EdgeInsets.all(14.w),
decoration: BoxDecoration( decoration: BoxDecoration(
@ -44,14 +34,14 @@ Widget buildQQMusicItem(
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDarkMode ? Colors.grey[800] : Colors.grey[100], color: isDarkMode ? Colors.grey[800] : Colors.grey[100],
borderRadius: BorderRadius.circular(8.r), borderRadius: BorderRadius.circular(8.r),
image: image.isNotEmpty image: song.albumPic!.isNotEmpty
? DecorationImage( ? DecorationImage(
image: NetworkImage(image), image: NetworkImage(song.albumPic!),
fit: BoxFit.cover, fit: BoxFit.cover,
) )
: null, : null,
), ),
child: image.isEmpty child: song.albumPic!.isEmpty
? Icon( ? Icon(
Icons.music_note, Icons.music_note,
size: 18.sp, size: 18.sp,
@ -65,7 +55,7 @@ Widget buildQQMusicItem(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
name, song.name,
style: TextStyle( style: TextStyle(
fontSize: 13.sp, fontSize: 13.sp,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
@ -77,7 +67,7 @@ Widget buildQQMusicItem(
), ),
SizedBox(height: 2.h), SizedBox(height: 2.h),
Text( Text(
singer, song.artist,
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: isDarkMode ? Colors.grey[400] : Colors.grey[600], color: isDarkMode ? Colors.grey[400] : Colors.grey[600],
@ -90,7 +80,7 @@ Widget buildQQMusicItem(
Obx(() { Obx(() {
// 使用QQ音乐服务的全局状态 // 使用QQ音乐服务的全局状态
final isThisPlaying = qqMusicService.isPlaying.value && final isThisPlaying = qqMusicService.isPlaying.value &&
qqMusicService.currentSong.value?.mid == id; qqMusicService.currentSong.value?.mid == song.mid;
// 计算播放进度 // 计算播放进度
final currentProgress = final currentProgress =
@ -109,27 +99,29 @@ Widget buildQQMusicItem(
onPlayPause: () async { onPlayPause: () async {
try { try {
if (qqMusicService.isPlaying.value) { if (qqMusicService.isPlaying.value) {
if (qqMusicService.currentSong.value?.mid == id) { if (qqMusicService.currentSong.value?.mid == song.mid) {
// 当前歌曲正在播放,暂停它 // 当前歌曲正在播放,暂停它
await qqMusicService.pauseMusic(); await qqMusicService.pauseMusic();
} else { } else {
final songMids = songs.map((s) => s.mid).toList();
// 其他歌曲正在播放,播放这首歌 // 其他歌曲正在播放,播放这首歌
await qqMusicService.playSongs( await qqMusicService.playSongs(
songMids: [id], songMids: songMids,
index: 0, index: index,
songList: [song], songList: [song],
currentSongModel: song, currentSongModel: song,
); );
} }
} else { } else {
if (qqMusicService.currentSong.value?.mid == id) { if (qqMusicService.currentSong.value?.mid == song.mid) {
// 当前歌曲已暂停,恢复播放 // 当前歌曲已暂停,恢复播放
await qqMusicService.resumeMusic(); await qqMusicService.resumeMusic();
} else { } else {
final songMids = songs.map((s) => s.mid).toList();
// 播放新歌曲 // 播放新歌曲
await qqMusicService.playSongs( await qqMusicService.playSongs(
songMids: [id], songMids: songMids,
index: 0, index: index,
songList: [song], songList: [song],
currentSongModel: song, currentSongModel: song,
); );
@ -155,23 +147,8 @@ Widget buildQQMusicItem(
} }
/// 构建音乐内容卡片 /// 构建音乐内容卡片
Widget buildQQMusicContent( Widget buildQQMusicContent(BuildContext context, List<SongModel> songs) {
BuildContext context, List<Map<String, dynamic>> playlist) {
final isDarkMode = Theme.of(context).brightness == Brightness.dark; final isDarkMode = Theme.of(context).brightness == Brightness.dark;
final qqMusicService = QqMusocService.to; // 使用QQ音乐全局服务
// 将播放列表转换为SongModel列表 - 修复字段名
final songList = playlist
.map((item) => SongModel(
mid: item["mid"] ?? "",
name: item["name"] ?? "未知歌曲",
artist: item["singer"] ?? "未知歌手", // 修复:使用 artist 而不是 singer
album: '', // 添加必需的 album 字段
duration: 0,
albumPic: item["pic"] ?? "", // 修复:使用 albumPic 而不是 pic
))
.toList();
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -213,17 +190,13 @@ Widget buildQQMusicContent(
const SizedBox(height: 10), const SizedBox(height: 10),
// 动态生成音乐条目 // 动态生成音乐条目
...playlist.asMap().entries.take(4).map((entry) { ...songs.asMap().entries.take(4).map((entry) {
final index = entry.key; final index = entry.key;
final item = entry.value; final item = entry.value;
final mid = item["mid"];
final name = item["name"] ?? "未知歌曲";
final singer = item["singer"] ?? "未知歌手";
final image = item["pic"] ?? "";
return Column( return Column(
children: [ children: [
buildQQMusicItem(context, mid, name, singer, image), buildQQMusicItem(context, songs, item, index),
if (index != playlist.length - 1) if (index != songs.length - 1)
Divider( Divider(
height: 1, height: 1,
thickness: 1, thickness: 1,
@ -239,7 +212,7 @@ Widget buildQQMusicContent(
child: TextButton( child: TextButton(
onPressed: () { onPressed: () {
// 跳转到完整歌单页面,传递完整的歌单数据 // 跳转到完整歌单页面,传递完整的歌单数据
Get.toNamed(Routes.qqmusic, arguments: {"playlist": playlist}); Get.toNamed(Routes.qqmusic, arguments: {"playlist": songs});
}, },
style: TextButton.styleFrom( style: TextButton.styleFrom(
minimumSize: Size.zero, minimumSize: Size.zero,

239
lib/modules/qqmusic/controllers/qqmusic_playlist_controller.dart

@ -12,112 +12,123 @@ class QQMusicPlaylistController extends GetxController {
final isLoggedIn = false.obs; final isLoggedIn = false.obs;
final userInfo = Rxn<Map<String, dynamic>>(); final userInfo = Rxn<Map<String, dynamic>>();
// 直接使用全局服务的状态 - 修复返回类型 // 界面维护的播放列表状态
RxBool get isPlaying => _qqMusicService.isPlaying; RxList<SongModel> playlist = <SongModel>[].obs;
RxInt currentIndex = 0.obs;
// 界面显示的当前歌曲(可能与实际播放的不同)
Rxn<SongModel> displayCurrentSong = Rxn<SongModel>();
// 界面播放状态(当前播放歌曲不在列表中时为未播放状态)
RxBool displayIsPlaying = false.obs;
// 从全局服务获取实际播放状态(仅用于同步)
RxBool get actualIsPlaying => _qqMusicService.isPlaying;
RxInt get currentPosition => _qqMusicService.currentPosition; RxInt get currentPosition => _qqMusicService.currentPosition;
RxInt get totalDuration => _qqMusicService.totalDuration; RxInt get totalDuration => _qqMusicService.totalDuration;
Rxn<SongModel> get currentSong => _qqMusicService.currentSong; Rxn<SongModel> get actualCurrentSong => _qqMusicService.currentSong;
RxList<SongModel> get playlist => _qqMusicService.playlist;
RxInt get currentIndex => _qqMusicService.currentIndex;
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
_initializePlaylist();
// 使用 WidgetsBinding.instance.addPostFrameCallback 延迟执行状态更新
WidgetsBinding.instance.addPostFrameCallback((_) {
_initializePlaylist();
});
print('🎵 [QQMusicPlaylistController] 控制器初始化完成'); print('🎵 [QQMusicPlaylistController] 控制器初始化完成');
} }
/// 初始化播放列表 - 延迟执行避免构建期间状态更新 /// 初始化播放列表
void _initializePlaylist() { void _initializePlaylist() {
// 从路由参数获取播放列表 // 从路由参数获取播放列表
final arguments = Get.arguments; final arguments = Get.arguments;
if (arguments != null && arguments['playlist'] != null) { if (arguments != null && arguments['playlist'] != null) {
final List<dynamic> playlistData = arguments['playlist']; final List<SongModel> songList = arguments['playlist'];
try { // try {
// 解析播放列表数据 // // 解析播放列表数据
final songList = playlistData // final songList = playlistData
.map((item) { // .map((item) {
try { // try {
return SongModel.fromJson(item); // return SongModel.fromJson(item);
} catch (e) { // } catch (e) {
Logger.e('QQMusicPlaylist', '解析歌曲数据失败: $e, 数据: $item'); // Logger.e('QQMusicPlaylist', '解析歌曲数据失败: $e, 数据: $item');
return null; // return null;
} // }
}) // })
.where((song) => song != null) // .where((song) => song != null)
.cast<SongModel>() // .cast<SongModel>()
.toList(); // .toList();
Logger.d('QQMusicPlaylist', '成功解析歌曲数量: ${songList.length}'); // Logger.d('QQMusicPlaylist', '成功解析歌曲数量: ${songList.length}');
// 更新播放列表
// 更新播放列表 playlist.assignAll(songList);
_qqMusicService.playlist.assignAll(songList); // 检查当前播放歌曲是否在列表中
_syncDisplayStateWithActualPlayback();
// 安全地设置当前歌曲 // } catch (e) {
if (songList.isNotEmpty) { // Logger.e('QQMusicPlaylist', '处理播放列表时发生异常: $e');
_qqMusicService.currentSong.value = songList.first; // _setDefaultDisplayState();
_qqMusicService.currentIndex.value = 0; // }
Logger.d('QQMusicPlaylist', '设置当前歌曲: ${songList.first.name}');
} else {
_qqMusicService.currentSong.value = null;
_qqMusicService.currentIndex.value = 0;
Logger.w('QQMusicPlaylist', '播放列表为空,无法设置当前歌曲');
}
} catch (e) {
Logger.e('QQMusicPlaylist', '处理播放列表时发生异常: $e');
// 确保状态一致性
_qqMusicService.currentSong.value = null;
_qqMusicService.currentIndex.value = 0;
}
} else { } else {
Logger.w('QQMusicPlaylist', '未接收到播放列表参数'); Logger.w('QQMusicPlaylist', '未接收到播放列表参数');
} _setDefaultDisplayState();
// 确保 playlist 初始化
if (_qqMusicService.playlist.isEmpty) {
Logger.w('QQMusicPlaylist', 'Playlist is empty on init');
} }
// 添加状态监听器 // 添加状态监听器
_qqMusicService.addListener(_onMusicStateChanged); _qqMusicService.addListener(_onMusicStateChanged);
// 界面初始化时同步播放状态和进度 // 界面初始化时同步播放状态和进度
_syncInitialState(); _qqMusicService.syncCurrentPlayInfo();
} }
/// 同步初始播放状态 - 移除 update() 调用 /// 同步显示状态与实际播放状态
Future<void> _syncInitialState() async { void _syncDisplayStateWithActualPlayback() {
try { if (playlist.isEmpty) {
Logger.d('QQMusicPlaylist', '开始同步初始播放状态'); _setDefaultDisplayState();
return;
}
// 同步当前播放信息 final actualSong = actualCurrentSong.value;
await _qqMusicService.syncCurrentPlayInfo();
// 如果当前有音乐在播放,启动状态监听 if (actualSong != null) {
if (_qqMusicService.isPlaying.value) { // 查找当前播放歌曲在列表中的位置
Logger.d('QQMusicPlaylist', '检测到音乐正在播放,启动状态监听'); final index = playlist.indexWhere((song) => song.mid == actualSong.mid);
_qqMusicService.startPlaybackStateMonitor();
}
// 移除这行,避免在构建期间调用 update() if (index != -1) {
// update(); // 当前播放歌曲在列表中
currentIndex.value = index;
displayCurrentSong.value = playlist[index];
displayIsPlaying.value = actualIsPlaying.value;
Logger.d('QQMusicPlaylist', '当前播放歌曲在列表中,索引: $index');
} else {
// 当前播放歌曲不在列表中,显示列表第一个,状态为未播放
_setDefaultDisplayState();
Logger.d('QQMusicPlaylist', '当前播放歌曲不在列表中,显示默认状态');
}
} else {
// 没有当前播放歌曲,显示列表第一个,状态为未播放
_setDefaultDisplayState();
Logger.d('QQMusicPlaylist', '无当前播放歌曲,显示默认状态');
}
}
Logger.d('QQMusicPlaylist', '初始状态同步完成'); /// 设置默认显示状态
} catch (e) { void _setDefaultDisplayState() {
Logger.e('QQMusicPlaylist', '初始状态同步失败: $e'); if (playlist.isNotEmpty) {
currentIndex.value = 0;
displayCurrentSong.value = playlist.first;
displayIsPlaying.value = false; // 默认为未播放状态
Logger.d('QQMusicPlaylist', '设置默认显示状态: ${playlist.first.name}');
} else {
currentIndex.value = 0;
displayCurrentSong.value = null;
displayIsPlaying.value = false;
Logger.w('QQMusicPlaylist', '播放列表为空,无法设置默认状态');
} }
} }
/// 音乐状态变化回调 - 使用 SchedulerBinding 延迟更新 /// 音乐状态变化回调
void _onMusicStateChanged() { void _onMusicStateChanged() {
// 使用 SchedulerBinding 确保在构建完成后再更新
SchedulerBinding.instance.addPostFrameCallback((_) { SchedulerBinding.instance.addPostFrameCallback((_) {
if (!isClosed) { if (!isClosed) {
// 重新同步显示状态
_syncDisplayStateWithActualPlayback();
update(); update();
} }
}); });
@ -133,7 +144,7 @@ class QQMusicPlaylistController extends GetxController {
/// 播放歌曲 /// 播放歌曲
Future<void> playSong(SongModel song, {List<SongModel>? songList}) async { Future<void> playSong(SongModel song, {List<SongModel>? songList}) async {
try { try {
// 如果没有传入歌曲列表,使用当前播放列表 // 使用传入的歌曲列表或当前播放列表
final List<SongModel> finalSongList = songList ?? playlist.toList(); final List<SongModel> finalSongList = songList ?? playlist.toList();
final songMids = finalSongList.map((s) => s.mid).toList(); final songMids = finalSongList.map((s) => s.mid).toList();
final playIndex = finalSongList.indexOf(song); final playIndex = finalSongList.indexOf(song);
@ -149,6 +160,7 @@ class QQMusicPlaylistController extends GetxController {
); );
if (result['success'] == true) { if (result['success'] == true) {
// 播放成功后,如果歌曲不在当前列表中,保持列表显示状态不变
Get.snackbar('开始播放', song.name); Get.snackbar('开始播放', song.name);
} else { } else {
Get.snackbar('播放失败', result['error'] ?? '未知错误'); Get.snackbar('播放失败', result['error'] ?? '未知错误');
@ -156,6 +168,10 @@ class QQMusicPlaylistController extends GetxController {
return; return;
} }
// 歌曲在当前列表中,更新界面状态
currentIndex.value = playIndex;
displayCurrentSong.value = song;
final result = await _qqMusicService.playSongs( final result = await _qqMusicService.playSongs(
songMids: songMids, songMids: songMids,
index: playIndex, index: playIndex,
@ -164,41 +180,102 @@ class QQMusicPlaylistController extends GetxController {
); );
if (result['success'] == true) { if (result['success'] == true) {
displayIsPlaying.value = true;
_qqMusicService.syncCurrentPlayInfo();
Get.snackbar('开始播放', song.name); Get.snackbar('开始播放', song.name);
} else { } else {
displayIsPlaying.value = false;
Get.snackbar('播放失败', result['error'] ?? '未知错误'); Get.snackbar('播放失败', result['error'] ?? '未知错误');
} }
} catch (e) { } catch (e) {
displayIsPlaying.value = false;
Get.snackbar('播放失败', e.toString()); Get.snackbar('播放失败', e.toString());
} }
} }
/// 播放列表中的指定歌曲
Future<void> playPlaylistSong(int index) async {
if (index >= 0 && index < playlist.length) {
await playSong(playlist[index]);
}
}
/// 暂停/继续播放 /// 暂停/继续播放
Future<void> togglePlayPause() async { Future<void> togglePlayPause() async {
if (isPlaying.value) { // 检查当前显示的歌曲是否正在播放
await _qqMusicService.pauseMusic(); final displaySong = displayCurrentSong.value;
final actualSong = actualCurrentSong.value;
if (displaySong != null &&
actualSong != null &&
displaySong.mid == actualSong.mid) {
// 显示的歌曲正在播放,执行暂停/继续
if (actualIsPlaying.value) {
await _qqMusicService.pauseMusic();
displayIsPlaying.value = false;
} else {
await _qqMusicService.resumeMusic();
displayIsPlaying.value = true;
}
} else { } else {
await _qqMusicService.resumeMusic(); // 显示的歌曲不是当前播放的,播放显示的歌曲
if (displaySong != null) {
await playSong(displaySong);
}
} }
} }
/// 下一首 /// 下一首(列表内)
Future<void> nextSong() async { Future<void> nextSong() async {
await _qqMusicService.skipToNext(); if (playlist.isNotEmpty) {
final nextIndex = (currentIndex.value + 1) % playlist.length;
await playPlaylistSong(nextIndex);
}
} }
/// 上一首 /// 上一首(列表内)
Future<void> previousSong() async { Future<void> previousSong() async {
await _qqMusicService.skipToPrevious(); if (playlist.isNotEmpty) {
final prevIndex =
currentIndex.value > 0 ? currentIndex.value - 1 : playlist.length - 1;
await playPlaylistSong(prevIndex);
}
} }
/// 停止播放 /// 停止播放
Future<void> stopMusic() async { Future<void> stopMusic() async {
await _qqMusicService.stopMusic(); await _qqMusicService.stopMusic();
displayIsPlaying.value = false;
} }
/// 格式化时间 /// 格式化时间
String formatDuration(int milliseconds) { String formatDuration(int milliseconds) {
return _qqMusicService.formatDuration(milliseconds); return _qqMusicService.formatDuration(milliseconds);
} }
/// 获取当前显示的播放状态(用于UI显示)
bool get isCurrentSongPlaying {
final displaySong = displayCurrentSong.value;
final actualSong = actualCurrentSong.value;
// 只有当显示的歌曲与实际播放的歌曲相同时,才显示播放状态
if (displaySong != null &&
actualSong != null &&
displaySong.mid == actualSong.mid) {
return actualIsPlaying.value;
}
return false;
}
/// 检查歌曲是否在当前播放列表中
bool isSongInPlaylist(SongModel song) {
return playlist.any((s) => s.mid == song.mid);
}
/// 更新播放列表(支持多个播放列表场景)
void updatePlaylist(List<SongModel> newPlaylist) {
playlist.assignAll(newPlaylist);
_syncDisplayStateWithActualPlayback();
Logger.d('QQMusicPlaylist', '播放列表已更新,歌曲数量: ${newPlaylist.length}');
}
} }

61
lib/modules/qqmusic/views/qqmusic_playlist_view.dart

@ -26,7 +26,7 @@ class QqmusicPlaylistView extends GetView<QQMusicPlaylistController> {
elevation: 0, elevation: 0,
), ),
backgroundColor: isDarkMode ? Colors.black : Colors.grey[50], backgroundColor: isDarkMode ? Colors.black : Colors.grey[50],
body: controller.playlist.isEmpty || controller.currentSong.value == null body: controller.playlist.isEmpty
? Center( ? Center(
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
@ -71,9 +71,9 @@ class QqmusicPlaylistView extends GetView<QQMusicPlaylistController> {
Widget _buildCurrentPlayingSection(bool isDarkMode) { Widget _buildCurrentPlayingSection(bool isDarkMode) {
return SingleChildScrollView( return SingleChildScrollView(
child: Obx(() { child: Obx(() {
// 添加空值检查 // 使用 displayCurrentSong 而不是 actualCurrentSong
final currentSong = controller.currentSong.value; final displayCurrentSong = controller.displayCurrentSong.value;
if (currentSong == null) { if (displayCurrentSong == null) {
return Container( return Container(
padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 12.h), padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 12.h),
child: Column( child: Column(
@ -102,12 +102,13 @@ class QqmusicPlaylistView extends GetView<QQMusicPlaylistController> {
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
// 封面图片 - 现在安全了 // 封面图片 - 使用 displayCurrentSong
_buildCoverImage(currentSong.albumPic ?? '', isDarkMode, _buildCoverImage(displayCurrentSong.albumPic ?? '', isDarkMode,
size: 110.w), size: 110.w),
SizedBox(height: 12.h), SizedBox(height: 12.h),
// 歌曲信息 - 现在安全了 // 歌曲信息 - 使用 displayCurrentSong
_buildSongInfo(currentSong.name, currentSong.artist, isDarkMode), _buildSongInfo(displayCurrentSong.name, displayCurrentSong.artist,
isDarkMode),
SizedBox(height: 16.h), SizedBox(height: 16.h),
// 进度条 // 进度条
_buildProgressBar(isDarkMode), _buildProgressBar(isDarkMode),
@ -259,18 +260,18 @@ class QqmusicPlaylistView extends GetView<QQMusicPlaylistController> {
SizedBox(width: 14.w), SizedBox(width: 14.w),
// 播放按钮 // 播放按钮
Obx(() { Obx(() {
// 使用 currentSong 的 mid 来判断是否是当前播放的歌曲 // 使用 actualCurrentSong 的 mid 来判断是否是当前播放的歌曲
final isThisPlaying = controller.isPlaying.value && final isThactualIsPlaying = controller.actualIsPlaying.value &&
controller.currentSong.value?.mid == song.mid; controller.actualCurrentSong.value?.mid == song.mid;
final currentProgress = isThisPlaying final currentProgress = isThactualIsPlaying
? controller.totalDuration.value > 0 ? controller.totalDuration.value > 0
? controller.currentPosition.value / ? controller.currentPosition.value /
controller.totalDuration.value controller.totalDuration.value
: 0.0 : 0.0
: 0.0; : 0.0;
return CircularProgressButton( return CircularProgressButton(
isPlaying: isThisPlaying, isPlaying: isThactualIsPlaying,
progress: currentProgress, progress: currentProgress,
primaryColor: Theme.of(context).primaryColor, primaryColor: Theme.of(context).primaryColor,
backgroundColor: Colors.grey, backgroundColor: Colors.grey,
@ -279,11 +280,11 @@ class QqmusicPlaylistView extends GetView<QQMusicPlaylistController> {
onPlayPause: () async { onPlayPause: () async {
try { try {
Logger.d('MusicPlaylistView', Logger.d('MusicPlaylistView',
'播放按钮被点击,当前播放状态: ${controller.isPlaying.value}'); '播放按钮被点击,当前播放状态: ${controller.actualIsPlaying.value}');
Logger.d('MusicPlaylistView', Logger.d('MusicPlaylistView',
'当前歌曲ID: ${controller.currentSong.value?.mid}, 点击歌曲ID: ${song.mid}'); '当前歌曲ID: ${controller.actualCurrentSong.value?.mid}, 点击歌曲ID: ${song.mid}');
if (controller.isPlaying.value) { if (controller.actualIsPlaying.value) {
if (controller.currentSong.value?.mid == song.mid) { if (controller.actualCurrentSong.value?.mid == song.mid) {
Logger.d('MusicPlaylistView', '暂停当前播放的歌曲'); Logger.d('MusicPlaylistView', '暂停当前播放的歌曲');
await controller.togglePlayPause(); await controller.togglePlayPause();
} else { } else {
@ -298,7 +299,7 @@ class QqmusicPlaylistView extends GetView<QQMusicPlaylistController> {
Logger.e('MusicPlaylistView', '播放音乐时发生错误: $e'); Logger.e('MusicPlaylistView', '播放音乐时发生错误: $e');
} }
}, },
onSeek: isThisPlaying ? (seekProgress) {} : null, onSeek: isThactualIsPlaying ? (seekProgress) {} : null,
); );
}), }),
], ],
@ -431,11 +432,11 @@ class QqmusicPlaylistView extends GetView<QQMusicPlaylistController> {
// 构建迷你播放器 - 参考qqmusic_test的设计 // 构建迷你播放器 - 参考qqmusic_test的设计
Widget _buildMiniPlayer(bool isDarkMode) { Widget _buildMiniPlayer(bool isDarkMode) {
return Obx(() { return Obx(() {
if (controller.currentSong.value == null) { if (controller.actualCurrentSong.value == null) {
return const SizedBox.shrink(); return const SizedBox.shrink();
} }
final song = controller.currentSong.value!; final song = controller.actualCurrentSong.value!;
return Container( return Container(
height: 80.h, height: 80.h,
decoration: BoxDecoration( decoration: BoxDecoration(
@ -506,7 +507,7 @@ class QqmusicPlaylistView extends GetView<QQMusicPlaylistController> {
), ),
IconButton( IconButton(
icon: Icon( icon: Icon(
controller.isPlaying.value controller.actualIsPlaying.value
? Icons.pause ? Icons.pause
: Icons.play_arrow, : Icons.play_arrow,
), ),
@ -569,7 +570,9 @@ class QqmusicPlaylistView extends GetView<QQMusicPlaylistController> {
}, },
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
icon: Icon( icon: Icon(
controller.isPlaying.value ? Icons.pause : Icons.play_arrow, controller.actualIsPlaying.value
? Icons.pause
: Icons.play_arrow,
size: 28.w, size: 28.w,
color: Colors.white, color: Colors.white,
), ),
@ -602,13 +605,13 @@ class QqmusicPlaylistView extends GetView<QQMusicPlaylistController> {
} }
// 播放/暂停切换 // 播放/暂停切换
Future<void> _togglePlayPause(AgentController controller) async { // Future<void> _togglePlayPause() async {
if (controller.isPlaying.value) { // if (controller.actualIsPlaying.value) {
await controller.musicPause(); // await controller.musicPause();
} else { // } else {
await controller.musicResume(); // await controller.musicResume();
} // }
} // }
// 播放上一曲 // 播放上一曲
Future<void> _playPrevious( Future<void> _playPrevious(

Loading…
Cancel
Save