feat(playlist): 歌单变更与歌单内元数据实时刷新

两个边界场景:
1) 新建/重命名/删除歌单、加入/移除歌曲后,主页歌单页不刷新
2) 歌单详情页里歌曲补全元数据后,标题/封面不更新

- 新增 PlaylistEvents(void 事件)
- PlaylistRepository 的创建/重命名/删除/批量加入/移除后 publish
- 主页订阅后重新拉取歌单摘要
- 歌单详情页订阅 MetadataEvents,按 path 就地更新行
This commit is contained in:
2026-11-01 16:32:35 +08:00
parent 653c1f5563
commit e10be527cb
4 changed files with 65 additions and 0 deletions
+28
View File
@@ -1,3 +1,4 @@
import 'dart:async';
// lib/pages/playlist_detail_page.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
@@ -5,6 +6,7 @@ import 'package:provider/provider.dart';
import '../database/song_database.dart';
import '../repositories/playlist_repository.dart';
import '../services/audio_service.dart';
import '../services/metadata_events.dart';
import '../widgets/song_artwork.dart';
/// 歌单详情:展示歌单内歌曲,支持播放全部 / 单曲播放 / 移除
@@ -41,14 +43,40 @@ class _PlaylistDetailPageState extends State<PlaylistDetailPage> {
final SongDatabase _db = SongDatabase();
List<_SongRow> _songs = [];
StreamSubscription<MetadataUpdate>? _metaSub;
bool _loading = true;
@override
void initState() {
super.initState();
_metaSub = MetadataEvents().stream.listen(_onMetadataUpdate);
_load();
}
@override
void dispose() {
_metaSub?.cancel();
super.dispose();
}
/// 歌单里的歌补全元数据后,就地更新对应行
void _onMetadataUpdate(MetadataUpdate update) {
final index = _songs.indexWhere((item) => item.path == update.path);
if (index < 0 || !mounted) return;
final row = update.row;
final title = (row['title'] as String?)?.trim() ?? '';
final artist = (row['artist'] as String?)?.trim() ?? '';
final artwork = (row['artwork_path'] as String?)?.trim() ?? '';
final old = _songs[index];
setState(() {
_songs[index] = _SongRow(
path: old.path,
title: title.isNotEmpty ? title : old.title,
artist: artist.isNotEmpty ? artist : old.artist,
artworkPath: artwork.isNotEmpty ? artwork : old.artworkPath,
);
});
}
Future<void> _load() async {
setState(() => _loading = true);
try {