// lib/widgets/add_to_playlist_sheet.dart import 'package:flutter/material.dart'; import '../models/playlist_summary.dart'; import '../repositories/playlist_repository.dart'; import '../services/route_manager.dart'; /// 把一首歌加入歌单的底部弹层。 /// /// 视觉先保持系统样式,等设计定稿后只换这个文件即可, /// 调用方(文件列表长按)不用改。 Future showAddToPlaylistSheet( BuildContext context, { required String songPath, }) async { final repo = PlaylistRepository(); List playlists; try { playlists = await repo.getSummaries(); } catch (e) { if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('读取歌单失败: $e')), ); } return; } if (!context.mounted) return; RouteManager().setTemporarilyHidden(true); try { await showModalBottomSheet( context: context, backgroundColor: const Color(0xFF1A1F1E), builder: (sheetContext) { return SafeArea( minimum: const EdgeInsets.only(bottom: 12), child: Column( mainAxisSize: MainAxisSize.min, children: [ const Padding( padding: EdgeInsets.fromLTRB(20, 18, 20, 8), child: Align( alignment: Alignment.centerLeft, child: Text( '加入歌单', style: TextStyle( color: Colors.white, fontSize: 16, fontWeight: FontWeight.w500, ), ), ), ), ListTile( leading: const Icon(Icons.add, color: Color(0xFFB8D4D0)), title: const Text( '新建歌单', style: TextStyle(color: Color(0xFFB8D4D0)), ), onTap: () async { Navigator.pop(sheetContext); await _createPlaylistAndAdd(context, repo, songPath); }, ), const Divider(height: 1, color: Colors.white12), if (playlists.isEmpty) const Padding( padding: EdgeInsets.symmetric(vertical: 24), child: Text( '还没有歌单,先新建一个', style: TextStyle(color: Colors.grey, fontSize: 13), ), ) else ConstrainedBox( constraints: const BoxConstraints(maxHeight: 320), child: ListView.builder( shrinkWrap: true, itemCount: playlists.length, itemBuilder: (context, index) { final playlist = playlists[index]; return ListTile( leading: const Icon( Icons.queue_music, color: Color(0xFFB8D4D0), ), title: Text( playlist.name, style: const TextStyle(color: Colors.white), ), subtitle: Text( '${playlist.songCount} 首', style: const TextStyle( color: Colors.grey, fontSize: 12), ), onTap: () async { final added = await repo.addSongs( playlist.id, [songPath], ); if (!sheetContext.mounted) return; Navigator.pop(sheetContext); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(added > 0 ? '已加入「${playlist.name}」' : '这首歌已经在「${playlist.name}」里了'), ), ); }, ); }, ), ), const SizedBox(height: 16), ], ), ); }, ); } finally { RouteManager().setTemporarilyHidden(false); } } Future _createPlaylistAndAdd( BuildContext context, PlaylistRepository repo, String songPath, ) async { final controller = TextEditingController(); final name = await showDialog( context: context, builder: (dialogContext) => AlertDialog( backgroundColor: const Color(0xFF1A1F1E), title: const Text('新建歌单', style: TextStyle(color: Colors.white)), content: TextField( controller: controller, autofocus: true, style: const TextStyle(color: Colors.white), decoration: const InputDecoration(hintText: '歌单名称'), ), actions: [ TextButton( onPressed: () => Navigator.pop(dialogContext), child: const Text('取消'), ), TextButton( onPressed: () => Navigator.pop(dialogContext, controller.text.trim()), child: const Text('创建'), ), ], ), ); if (name == null || name.isEmpty) return; try { final playlist = await repo.createPlaylist(name); await repo.addSongs(playlist.id, [songPath]); if (!context.mounted) return; ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('已新建「$name」并加入这首歌')), ); } catch (e) { if (!context.mounted) return; ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('新建歌单失败: $e')), ); } }