// lib/controllers/playback_controller.dart import 'package:flutter/foundation.dart'; // ⭐ 添加 import '../services/audio_service.dart'; import '../services/webdav_service.dart'; import '../database/song_database.dart'; class PlaybackController { static final PlaybackController _instance = PlaybackController._internal(); factory PlaybackController() => _instance; PlaybackController._internal(); final AudioService _audioService = AudioService(); final SongDatabase _db = SongDatabase(); // ════════════════════════════════════════════════════════════ // 从 WebDAV 目录播放(点击歌曲) // ════════════════════════════════════════════════════════════ Future playFromWebDAV({ required String directoryPath, required String clickedSongPath, required List allItems, }) async { // 1. 过滤出所有音乐文件(去掉目录) final musicFiles = allItems.where((item) => !item.isDirectory).toList() ..sort((a, b) => a.name.toLowerCase().compareTo(b.name.toLowerCase())); if (musicFiles.isEmpty) return; // 2. 调试信息 debugPrint('🎯 [PlaybackController] musicFiles:'); for (int i = 0; i < musicFiles.length; i++) { debugPrint(' $i: ${musicFiles[i].path}'); } debugPrint('🎯 [PlaybackController] clickedSongPath: $clickedSongPath'); // 3. 找到点击歌曲在音乐文件列表中的位置 final clickedIndex = musicFiles.indexWhere((item) => item.path == clickedSongPath); debugPrint('🎯 [PlaybackController] clickedIndex: $clickedIndex'); if (clickedIndex == -1) { debugPrint( '⚠️ [PlaybackController] clicked song not found, fallback to single play'); await _playSingleSong(clickedSongPath); return; } // 4. 构建 Song 队列 final queue = await _buildSongQueue(musicFiles); // 5. 应用播放模式 final playMode = _audioService.playMode; List finalQueue = List.from(queue); int startIndex = clickedIndex; if (playMode == PlayMode.shuffle) { final shuffled = List.from(queue)..shuffle(); startIndex = shuffled.indexWhere((s) => s.id == clickedSongPath); if (startIndex == -1) startIndex = 0; finalQueue = shuffled; } debugPrint( '🎯 [PlaybackController] finalQueue length: ${finalQueue.length}, startIndex: $startIndex'); _audioService.setQueue(finalQueue, startIndex: startIndex); } // ════════════════════════════════════════════════════════════ // 从 WebDAV 目录播放(全部播放) // ════════════════════════════════════════════════════════════ Future playAllFromWebDAV({ required String directoryPath, required List allItems, }) async { final musicFiles = allItems.where((item) => !item.isDirectory).toList() ..sort((a, b) => a.name.toLowerCase().compareTo(b.name.toLowerCase())); if (musicFiles.isEmpty) return; final queue = await _buildSongQueue(musicFiles); final playMode = _audioService.playMode; List finalQueue = List.from(queue); if (playMode == PlayMode.shuffle) { finalQueue = List.from(queue)..shuffle(); } _audioService.setQueue(finalQueue, startIndex: 0); } // ════════════════════════════════════════════════════════════ // 单曲播放(fallback) // ════════════════════════════════════════════════════════════ Future _playSingleSong(String songPath) async { debugPrint('🎯 [PlaybackController] _playSingleSong: $songPath'); final url = WebDAVService.instance.getFileUrl(songPath); final dbSong = await _db.getSongByPath(songPath); final song = Song( id: songPath, title: dbSong?['title'] as String? ?? songPath.split('/').last.replaceAll(RegExp(r'\.[^.]*$'), ''), artist: dbSong?['artist'] as String? ?? '未知艺术家', url: url, ); _audioService.playSong(song); } // ════════════════════════════════════════════════════════════ // 构建 Song 队列 // ════════════════════════════════════════════════════════════ Future> _buildSongQueue(List musicFiles) async { final queue = []; for (final item in musicFiles) { final dbSong = await _db.getSongByPath(item.path); final url = WebDAVService.instance.getFileUrl(item.path); if (dbSong != null) { queue.add(Song( id: item.path, title: dbSong['title'] as String? ?? item.name.replaceAll(RegExp(r'\.[^.]*$'), ''), artist: dbSong['artist'] as String? ?? '未知艺术家', url: url, )); } else { queue.add(Song( id: item.path, title: item.name.replaceAll(RegExp(r'\.[^.]*$'), ''), artist: '未知艺术家', url: url, )); } } return queue; } // ════════════════════════════════════════════════════════════ // 播放控制透传 // ════════════════════════════════════════════════════════════ void next() => _audioService.next(); void previous() => _audioService.previous(); void togglePlayMode() => _audioService.togglePlayMode(); PlayMode get playMode => _audioService.playMode; }