数据层: - PlaylistSummary(歌单名/歌曲数/封面),DB 用一条 SQL 取摘要, 封面取歌单内第一首有封面的歌 - PlaylistRepository.getSummaries() / addSongs()(批量加入并去重) - 修复 AudioService.playPlaylist:之前把文件路径直接当 URL, 歌单播放必然失败;现在用 WebDAVService.getFileUrl 构造 入口(视觉为临时实现,等设计稿替换): - 文件列表长按 -> "加入歌单" 底部弹层 - 可在弹层里新建歌单并直接加入 真机验证:长按歌曲 -> 新建 "TL" -> 数据库 playlists/playlist_songs 均有记录。 测试:新增 playlist_summary 4 个用例,累计 29 个全绿。
148 lines
5.3 KiB
Dart
148 lines
5.3 KiB
Dart
// lib/repositories/playlist_repository.dart
|
|
import 'dart:math';
|
|
import '../database/song_database.dart';
|
|
import '../models/playlist.dart';
|
|
import '../models/playlist_summary.dart';
|
|
import '../services/audio_service.dart';
|
|
|
|
class PlaylistRepository {
|
|
final SongDatabase _db = SongDatabase();
|
|
|
|
String _generateId() {
|
|
const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
|
|
final random = Random();
|
|
return String.fromCharCodes(
|
|
Iterable.generate(
|
|
16, (_) => chars.codeUnitAt(random.nextInt(chars.length))),
|
|
);
|
|
}
|
|
|
|
// ════════════════════════════════════════════════════════════
|
|
// 歌单操作
|
|
// ════════════════════════════════════════════════════════════
|
|
|
|
Future<List<Playlist>> getAllPlaylists() async {
|
|
final data = await _db.getAllPlaylists();
|
|
return data.map((e) => Playlist.fromJson(e)).toList();
|
|
}
|
|
|
|
Future<Playlist?> getPlaylist(String id) async {
|
|
final data = await _db.getPlaylist(id);
|
|
if (data == null) return null;
|
|
return Playlist.fromJson(data);
|
|
}
|
|
|
|
Future<Playlist> createPlaylist(String name) async {
|
|
final playlist = Playlist(id: _generateId(), name: name);
|
|
await _db.insertPlaylist(playlist.toJson());
|
|
return playlist;
|
|
}
|
|
|
|
/// 歌单列表摘要(歌曲数 + 封面),给主页/列表页用
|
|
Future<List<PlaylistSummary>> getSummaries() async {
|
|
final rows = await _db.getPlaylistSummaries();
|
|
return rows.map(PlaylistSummary.fromRow).toList();
|
|
}
|
|
|
|
/// 批量加入歌曲(自动跳过歌单里已有的,避免打乱顺序)
|
|
Future<int> addSongs(String playlistId, List<String> songIds) async {
|
|
if (songIds.isEmpty) return 0;
|
|
final existing = (await getPlaylistSongIds(playlistId)).toSet();
|
|
var added = 0;
|
|
for (final id in songIds) {
|
|
if (existing.contains(id)) continue;
|
|
await _db.addSongToPlaylist(playlistId, id);
|
|
existing.add(id);
|
|
added++;
|
|
}
|
|
return added;
|
|
}
|
|
Future<void> updatePlaylistName(String id, String newName) async {
|
|
await _db.updatePlaylist(id, {
|
|
'name': newName,
|
|
'updated_at': DateTime.now().millisecondsSinceEpoch,
|
|
});
|
|
}
|
|
|
|
// ⭐ 新增:更新播放模式
|
|
Future<void> updatePlaylistPlayMode(String id, PlayMode playMode) async {
|
|
await _db.updatePlaylist(id, {
|
|
// ⭐ 修改前:_playModeToString
|
|
// 'play_mode': _playModeToString(playMode),
|
|
|
|
// ⭐ 修改后:用公开静态方法
|
|
'play_mode': Playlist.playModeToString(playMode),
|
|
'updated_at': DateTime.now().millisecondsSinceEpoch,
|
|
});
|
|
}
|
|
|
|
Future<void> deletePlaylist(String id) async {
|
|
await _db.deletePlaylist(id);
|
|
}
|
|
|
|
// ════════════════════════════════════════════════════════════
|
|
// 歌单歌曲操作
|
|
// ════════════════════════════════════════════════════════════
|
|
|
|
Future<List<String>> getPlaylistSongIds(String playlistId) async {
|
|
final data = await _db.getPlaylistSongs(playlistId);
|
|
return data.map((e) => e['song_id'] as String).toList();
|
|
}
|
|
|
|
Future<void> addSong(String playlistId, String songId) async {
|
|
await _db.addSongToPlaylist(playlistId, songId);
|
|
}
|
|
|
|
Future<void> removeSong(String playlistId, String songId) async {
|
|
await _db.removeSongFromPlaylist(playlistId, songId);
|
|
}
|
|
|
|
Future<void> reorderSongs(
|
|
String playlistId, int oldIndex, int newIndex) async {
|
|
if (oldIndex == newIndex) return;
|
|
final songs = await _db.getPlaylistSongs(playlistId);
|
|
if (oldIndex < 0 ||
|
|
oldIndex >= songs.length ||
|
|
newIndex < 0 ||
|
|
newIndex >= songs.length) {
|
|
return;
|
|
}
|
|
final items = songs.map((e) => e['song_id'] as String).toList();
|
|
final item = items.removeAt(oldIndex);
|
|
items.insert(newIndex, item);
|
|
for (int i = 0; i < items.length; i++) {
|
|
await _db.removeSongFromPlaylist(playlistId, items[i]);
|
|
await _db.addSongToPlaylist(playlistId, items[i], orderIndex: i);
|
|
}
|
|
}
|
|
|
|
Future<void> clearPlaylist(String playlistId) async {
|
|
await _db.clearPlaylist(playlistId);
|
|
}
|
|
|
|
// ════════════════════════════════════════════════════════════
|
|
// 收藏操作
|
|
// ════════════════════════════════════════════════════════════
|
|
|
|
Future<List<String>> getFavorites() async {
|
|
final data = await _db.getFavorites();
|
|
return data.map((e) => e['song_id'] as String).toList();
|
|
}
|
|
|
|
Future<bool> isFavorite(String songId) async {
|
|
return await _db.isFavorite(songId);
|
|
}
|
|
|
|
Future<void> addFavorite(String songId) async {
|
|
await _db.addFavorite(songId);
|
|
}
|
|
|
|
Future<void> removeFavorite(String songId) async {
|
|
await _db.removeFavorite(songId);
|
|
}
|
|
|
|
Future<void> toggleFavorite(String songId) async {
|
|
await _db.toggleFavorite(songId);
|
|
}
|
|
}
|