import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../library/database.dart'; import '../library/permissions.dart'; import '../services/navidrome_service.dart'; import 'library_stats.dart'; /// Settings-Tab: Bibliotheks-Statistik, Berechtigungen, Navidrome, Über Melo. class SettingsScreen extends StatefulWidget { const SettingsScreen({super.key}); @override State createState() => _SettingsScreenState(); } class _SettingsScreenState extends State { late final NavidromeService _navidrome = NavidromeService(); @override void initState() { super.initState(); _navidrome.ladeGespeicherteZugangsdaten(); } @override Widget build(BuildContext context) { final db = context.read(); return Scaffold( appBar: AppBar(title: const Text('Settings')), body: ListView( children: [ const _SectionLabel('Bibliothek'), StreamBuilder>( stream: db.watchSongs(), builder: (context, snapshot) { final songs = snapshot.data ?? const []; return Column( children: [ ListTile( leading: const Icon(Icons.library_music), title: Text('${songs.length} Songs in der Bibliothek'), ), ListTile( leading: const Icon(Icons.schedule), title: Text('${formatTotalDuration(songs)} Gesamtspieldauer'), ), ], ); }, ), const Divider(height: 1), const _SectionLabel('Musikserver'), ListTile( leading: const Icon(Icons.cloud_circle), title: const Text('🌐 Navidrome'), subtitle: _navidrome.istVerbunden ? const Text('✅ Verbunden') : const Text('Nicht verbunden'), trailing: _navidrome.istVerbunden ? IconButton( icon: const Icon(Icons.logout), onPressed: () => _trennNavidrome(), ) : IconButton( icon: const Icon(Icons.login), onPressed: () => _zeigeNavidromeDialog(), ), ), const Divider(height: 1), const _SectionLabel('Berechtigungen'), ListTile( leading: const Icon(Icons.mic_none), title: const Text('Musik-Berechtigung'), trailing: TextButton( onPressed: openMusicPermissionSettings, child: const Text('Einstellungen öffnen'), ), ), const Divider(height: 1), const _SectionLabel('Über Melo'), const ListTile( leading: Icon(Icons.info_outline), title: Text('Melo'), subtitle: Text('Deine Musik. Offline. Kein Abo.'), ), ], ), ); } void _zeigeNavidromeDialog() { final urlCtrl = TextEditingController(); final userCtrl = TextEditingController(); final passCtrl = TextEditingController(); bool verbindet = false; String? fehler; showDialog( context: context, builder: (ctx) => StatefulBuilder( builder: (ctx, setDialogState) => AlertDialog( backgroundColor: Colors.grey.shade900, title: const Text('🌐 Navidrome Verbinden', style: TextStyle(color: Colors.white, fontSize: 16)), content: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( controller: urlCtrl, style: const TextStyle(color: Colors.white), decoration: const InputDecoration( labelText: 'Server-URL', hintText: 'https://musik.example.com', labelStyle: TextStyle(color: Colors.grey), hintStyle: TextStyle(color: Colors.grey), border: OutlineInputBorder(), ), ), const SizedBox(height: 8), TextField( controller: userCtrl, style: const TextStyle(color: Colors.white), decoration: const InputDecoration( labelText: 'Benutzer', labelStyle: TextStyle(color: Colors.grey), border: OutlineInputBorder(), ), ), const SizedBox(height: 8), TextField( controller: passCtrl, style: const TextStyle(color: Colors.white), obscureText: true, decoration: const InputDecoration( labelText: 'Passwort', labelStyle: TextStyle(color: Colors.grey), border: OutlineInputBorder(), ), ), if (fehler != null) ...[ const SizedBox(height: 8), Text(fehler!, style: const TextStyle(color: Colors.red, fontSize: 12)), ], if (verbindet) const Padding( padding: EdgeInsets.only(top: 12), child: SizedBox( width: 20, height: 20, child: CircularProgressIndicator( strokeWidth: 2, color: Colors.redAccent), ), ), ], ), actions: [ TextButton( onPressed: () => Navigator.pop(ctx), child: const Text('Abbrechen')), TextButton( onPressed: verbindet ? null : () async { setDialogState(() => verbindet = true); _navidrome.setCredentials( urlCtrl.text, userCtrl.text, passCtrl.text); final ok = await _navidrome.ping(); setDialogState(() => verbindet = false); if (ok && ctx.mounted) { await _navidrome.speichereZugangsdaten( urlCtrl.text, userCtrl.text, passCtrl.text); if (ctx.mounted) Navigator.pop(ctx); if (mounted) setState(() {}); } else if (ctx.mounted) { setDialogState(() => fehler = '❌ Verbindung fehlgeschlagen\nPrüfe URL + Zugangsdaten'); } }, child: const Text('Verbinden', style: TextStyle(color: Colors.redAccent)), ), ], ), ), ).then((_) { urlCtrl.dispose(); userCtrl.dispose(); passCtrl.dispose(); }); } Future _trennNavidrome() async { await _navidrome.loescheZugangsdaten(); if (mounted) setState(() {}); } } /// Kleine graue Überschrift über einer Einstellungs-Gruppe. class _SectionLabel extends StatelessWidget { const _SectionLabel(this.label); final String label; @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.fromLTRB(16, 16, 16, 4), child: Text( label, style: const TextStyle( color: Colors.white54, fontSize: 12, fontWeight: FontWeight.bold, ), ), ); } }