两个边界场景: 1) 新建/重命名/删除歌单、加入/移除歌曲后,主页歌单页不刷新 2) 歌单详情页里歌曲补全元数据后,标题/封面不更新 - 新增 PlaylistEvents(void 事件) - PlaylistRepository 的创建/重命名/删除/批量加入/移除后 publish - 主页订阅后重新拉取歌单摘要 - 歌单详情页订阅 MetadataEvents,按 path 就地更新行
154 lines
5.5 KiB
Dart
154 lines
5.5 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/playlist_events.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());
|
|
PlaylistEvents().publish();
|
|
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++;
|
|
}
|
|
if (added > 0) PlaylistEvents().publish();
|
|
return added;
|
|
}
|
|
Future<void> updatePlaylistName(String id, String newName) async {
|
|
await _db.updatePlaylist(id, {
|
|
'name': newName,
|
|
'updated_at': DateTime.now().millisecondsSinceEpoch,
|
|
});
|
|
PlaylistEvents().publish();
|
|
}
|
|
|
|
// ⭐ 新增:更新播放模式
|
|
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);
|
|
PlaylistEvents().publish();
|
|
}
|
|
|
|
// ════════════════════════════════════════════════════════════
|
|
// 歌单歌曲操作
|
|
// ════════════════════════════════════════════════════════════
|
|
|
|
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);
|
|
PlaylistEvents().publish();
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|