import 'dart:io'; import 'package:flutter/material.dart'; import '../models/song.dart'; import '../database/db_helper.dart'; import '../services/id3_reader.dart'; import '../utils/farb_theme.dart'; class MetadatenDialog extends StatefulWidget { final Song song; const MetadatenDialog({super.key, required this.song}); @override State createState() => _MetadatenDialogState(); } class _MetadatenDialogState extends State { late TextEditingController _titelCtrl; late TextEditingController _kuenstlerCtrl; late TextEditingController _albumCtrl; late TextEditingController _jahrCtrl; late TextEditingController _genreCtrl; final DbHelper _db = DbHelper(); bool _id3Geladen = false; @override void initState() { super.initState(); _titelCtrl = TextEditingController(text: widget.song.titel); _kuenstlerCtrl = TextEditingController(text: widget.song.kuenstler); _albumCtrl = TextEditingController(text: widget.song.album); _jahrCtrl = TextEditingController(text: widget.song.jahr ?? ''); _genreCtrl = TextEditingController(text: widget.song.genre ?? ''); // Falls Song kein Jahr/Genre hat → aus ID3-Tags nachladen if ((widget.song.jahr == null || widget.song.jahr!.isEmpty) || (widget.song.genre == null || widget.song.genre!.isEmpty)) { _id3Nachladen(); } } void _id3Nachladen() { try { final tags = Id3Reader.lesen(widget.song.dateiPfad); if (!_id3Geladen) { final jahr = tags['jahr'] as String?; final genre = tags['genre'] as String?; if ((jahr != null && jahr.isNotEmpty) || (genre != null && genre.isNotEmpty)) { setState(() { if (jahr != null && jahr.isNotEmpty && _jahrCtrl.text.isEmpty) { _jahrCtrl.text = jahr; } if (genre != null && genre.isNotEmpty && _genreCtrl.text.isEmpty) { _genreCtrl.text = genre; } _id3Geladen = true; }); } } } catch (_) {} } @override void dispose() { _titelCtrl.dispose(); _kuenstlerCtrl.dispose(); _albumCtrl.dispose(); _jahrCtrl.dispose(); _genreCtrl.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return AlertDialog( backgroundColor: MeloTheme.dunkel1, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), title: const Row( children: [ Icon(Icons.edit_note, color: MeloTheme.rot, size: 24), SizedBox(width: 8), Text('Metadaten', style: TextStyle(color: Colors.white, fontSize: 18, fontWeight: FontWeight.w600)), ], ), content: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, children: [ // ── Cover-Bild (128×128) ── if (widget.song.coverPfad != null && widget.song.coverPfad!.isNotEmpty) _coverWidget(), // ── Editierbare Felder ── _sectionLabel('Bearbeiten'), const SizedBox(height: 8), _editCard( children: [ _field('Titel', _titelCtrl, Icons.music_note), const SizedBox(height: 12), _field('Künstler', _kuenstlerCtrl, Icons.person), const SizedBox(height: 12), _field('Album', _albumCtrl, Icons.album), const SizedBox(height: 12), _field('Jahr', _jahrCtrl, Icons.calendar_today), const SizedBox(height: 12), _field('Genre', _genreCtrl, Icons.category), ], ), const SizedBox(height: 20), // ── Read-Only Infos ── _sectionLabel('Informationen'), const SizedBox(height: 8), _infoCard( children: [ _infoZeile('Dauer', widget.song.dauerFormatiert, Icons.timer), const Divider(color: MeloTheme.dunkel2, height: 1), _infoZeile('Dateigröße', widget.song.groesseFormatiert, Icons.storage), const Divider(color: MeloTheme.dunkel2, height: 1), _infoZeile('Format', widget.song.dateiFormat, Icons.audio_file), ], ), ], ), ), actions: [ OutlinedButton( onPressed: () => Navigator.pop(context, false), style: OutlinedButton.styleFrom( foregroundColor: Colors.white54, side: const BorderSide(color: Colors.white24), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), ), child: const Text('Abbrechen'), ), const SizedBox(width: 8), ElevatedButton( onPressed: () => _speichern(), style: ElevatedButton.styleFrom( backgroundColor: MeloTheme.rot, foregroundColor: Colors.white, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), ), child: const Text('Speichern'), ), ], ); } // ── Cover-Bild ──────────────────────────────────────────────────────── Widget _coverWidget() { return Padding( padding: const EdgeInsets.only(bottom: 20), child: Center( child: Container( width: 128, height: 128, decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), border: Border.all(color: MeloTheme.rot, width: 2), boxShadow: [ BoxShadow(color: MeloTheme.rot.withValues(alpha: 0.25), blurRadius: 12, offset: const Offset(0, 4)), ], ), child: ClipRRect( borderRadius: BorderRadius.circular(10), child: Image.file( File(widget.song.coverPfad!), width: 128, height: 128, fit: BoxFit.cover, errorBuilder: (_, __, ___) => Container( color: MeloTheme.dunkel2, child: const Icon(Icons.broken_image, color: Colors.white38, size: 40), ), ), ), ), ), ); } // ── Section Label ───────────────────────────────────────────────────── Widget _sectionLabel(String text) { return Align( alignment: Alignment.centerLeft, child: Text( text, style: const TextStyle( color: MeloTheme.rot, fontSize: 12, fontWeight: FontWeight.w700, letterSpacing: 1.2, ), ), ); } // ── Edit Card ───────────────────────────────────────────────────────── Widget _editCard({required List children}) { return Container( width: double.infinity, padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: MeloTheme.dunkel2, borderRadius: BorderRadius.circular(14), border: Border.all(color: MeloTheme.rot.withValues(alpha: 0.2)), ), child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: children), ); } // ── Info Card ───────────────────────────────────────────────────────── Widget _infoCard({required List children}) { return Container( width: double.infinity, padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: MeloTheme.schwarz, borderRadius: BorderRadius.circular(14), border: Border.all(color: Colors.white12), ), child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: children), ); } // ── Eingabefeld ─────────────────────────────────────────────────────── Widget _field(String label, TextEditingController ctrl, IconData icon) { return TextField( controller: ctrl, style: const TextStyle(color: Colors.white, fontSize: 14), decoration: InputDecoration( prefixIcon: Icon(icon, color: MeloTheme.rot, size: 18), labelText: label, labelStyle: const TextStyle(color: Colors.grey), hintStyle: TextStyle(color: Colors.grey.withValues(alpha: 0.4)), filled: true, fillColor: MeloTheme.dunkel1, border: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: const BorderSide(color: Colors.white12), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: const BorderSide(color: Colors.white12), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: const BorderSide(color: MeloTheme.rot, width: 1.5), ), contentPadding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12), ), ); } // ── Read-Only Info-Zeile ────────────────────────────────────────────── Widget _infoZeile(String label, String wert, IconData icon) { return Padding( padding: const EdgeInsets.symmetric(vertical: 10), child: Row( children: [ Icon(icon, color: MeloTheme.rot, size: 18), const SizedBox(width: 10), Text( label, style: const TextStyle(color: Colors.white54, fontSize: 13), ), const Spacer(), Text( wert, style: const TextStyle(color: Colors.white, fontSize: 13, fontWeight: FontWeight.w500), ), ], ), ); } // ── Speichern ───────────────────────────────────────────────────────── Future _speichern() async { final id = widget.song.id; if (id == null) { if (mounted) Navigator.pop(context, false); return; } final titel = _titelCtrl.text.trim(); final kuenstler = _kuenstlerCtrl.text.trim(); final album = _albumCtrl.text.trim(); final jahr = _jahrCtrl.text.trim(); final genre = _genreCtrl.text.trim(); if (titel.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Titel darf nicht leer sein')), ); return; } await _db.metadatenAktualisieren( id, titel: titel, kuenstler: kuenstler, album: album, jahr: jahr.isEmpty ? null : jahr, genre: genre.isEmpty ? null : genre, ); if (mounted) Navigator.pop(context, true); } }