import 'dart:io'; import 'package:flutter/material.dart'; import '../models/song.dart'; import '../utils/farb_theme.dart'; import 'metadaten_dialog.dart'; import 'tag_auswahl_dialog.dart'; class SongTile extends StatelessWidget { final Song song; final bool istFavorit; final ValueChanged onFavoriteToggle; final ValueChanged onPlay; final VoidCallback onMetadataChanged; final ValueChanged? onAddToPlaylist; final ValueChanged? onErneutHerunterladen; final ValueChanged? onSpieleAlsNaechstes; final ValueChanged? onAmEndeHinzufuegen; const SongTile({ super.key, required this.song, required this.istFavorit, required this.onFavoriteToggle, required this.onPlay, required this.onMetadataChanged, this.onAddToPlaylist, this.onErneutHerunterladen, this.onSpieleAlsNaechstes, this.onAmEndeHinzufuegen, }); @override Widget build(BuildContext context) { final hatDatei = song.dateiPfad.isNotEmpty; final hatCover = song.coverPfad != null && File(song.coverPfad!).existsSync(); return ListTile( contentPadding: const EdgeInsets.symmetric(vertical: 2), leading: ClipRRect( borderRadius: BorderRadius.circular(10), child: Container( width: 44, height: 44, decoration: const BoxDecoration( gradient: LinearGradient(colors: [Color(0xFF1A0000), Color(0xFF660000)]), ), child: hatCover ? Image.file(File(song.coverPfad!), fit: BoxFit.cover) : const Center(child: Text('♪', style: TextStyle(fontSize: 18, color: Colors.white54))), ), ), title: Row( children: [ if (song.istKorrupt) const Padding( padding: EdgeInsets.only(right: 6), child: Text('⚠️', style: TextStyle(fontSize: 16)), ), Expanded( child: Text( song.titel, style: TextStyle( fontSize: 14, fontWeight: FontWeight.w500, color: song.istKorrupt ? MeloTheme.textSekundaer : Colors.white, decoration: song.istKorrupt ? TextDecoration.lineThrough : null, ), ), ), ], ), subtitle: Text(song.kuenstler, style: const TextStyle(fontSize: 12, color: MeloTheme.textSekundaer)), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ // ── Korrupt mit ytUrl: 🔄 Neu laden ── if (song.istKorrupt && song.ytUrl != null && onErneutHerunterladen != null) InkWell( borderRadius: BorderRadius.circular(50), onTap: () => onErneutHerunterladen!(song), child: const Padding( padding: EdgeInsets.all(6), child: Text('🔄', style: TextStyle(fontSize: 16)), ), ), InkWell( borderRadius: BorderRadius.circular(50), onTap: () async { final geaendert = await showDialog( context: context, builder: (_) => MetadatenDialog(song: song), ); if (geaendert == true) onMetadataChanged(); }, child: Padding( padding: const EdgeInsets.all(6), child: Icon(Icons.edit, size: 14, color: MeloTheme.textSekundaer), ), ), InkWell( borderRadius: BorderRadius.circular(50), onTap: () => showDialog( context: context, builder: (_) => TagAuswahlDialog( songId: song.id!, songTitel: song.titel, onChanged: onMetadataChanged, ), ), child: Padding( padding: const EdgeInsets.all(6), child: const Icon(Icons.label_outline, size: 14, color: MeloTheme.textSekundaer), ), ), if (onAddToPlaylist != null) InkWell( borderRadius: BorderRadius.circular(50), onTap: () => onAddToPlaylist!(song), child: Padding( padding: const EdgeInsets.all(6), child: const Icon(Icons.playlist_add, size: 14, color: MeloTheme.textSekundaer), ), ), InkWell( borderRadius: BorderRadius.circular(50), onTap: () => onFavoriteToggle(song), child: Padding( padding: const EdgeInsets.all(6), child: Icon( istFavorit ? Icons.favorite : Icons.favorite_border, size: 16, color: MeloTheme.rot, ), ), ), Text(song.dauerFormatiert, style: const TextStyle(fontSize: 12, color: MeloTheme.textSekundaer)), ], ), onTap: hatDatei ? () => onPlay(song) : null, onLongPress: (hatDatei && (onSpieleAlsNaechstes != null || onAmEndeHinzufuegen != null)) ? () => _zeigeKontextMenu(context) : null, ); } /// Kontextmenü per Long-Press: "Als Nächstes abspielen" + "Am Ende hinzufügen" void _zeigeKontextMenu(BuildContext context) { showModalBottomSheet( context: context, backgroundColor: MeloTheme.dunkel1, builder: (ctx) => SafeArea( child: Column( mainAxisSize: MainAxisSize.min, children: [ ListTile( leading: const Icon(Icons.playlist_play, color: MeloTheme.rot, size: 20), title: const Text( 'Als Nächstes abspielen', style: TextStyle(color: Colors.white, fontSize: 14), ), onTap: () { Navigator.pop(ctx); onSpieleAlsNaechstes?.call(song); }, ), if (onAmEndeHinzufuegen != null) ListTile( leading: const Icon(Icons.playlist_add, color: MeloTheme.rot, size: 20), title: const Text( 'Am Ende hinzufügen', style: TextStyle(color: Colors.white, fontSize: 14), ), onTap: () { Navigator.pop(ctx); onAmEndeHinzufuegen!(song); }, ), ], ), ), ); } }