import 'dart:io'; import 'package:flutter/material.dart'; import 'package:path_provider/path_provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../services/download_service.dart'; import '../utils/farb_theme.dart'; import '../services/melo_logger.dart'; class DownloadScreen extends StatefulWidget { final DownloadService downloader; final VoidCallback onSongsChanged; const DownloadScreen({ super.key, required this.downloader, required this.onSongsChanged, }); @override State createState() => _DownloadScreenState(); } class _DownloadScreenState extends State { final _urlController = TextEditingController(); bool _ladt = false; String? _fehler; String? _erfolg; String _speicherOrt = 'Intern (Documents/music)'; @override void initState() { super.initState(); _ladeSpeicherPfad(); } @override void dispose() { _urlController.dispose(); super.dispose(); } Future _ladeSpeicherPfad() async { final prefs = await SharedPreferences.getInstance(); final pfad = prefs.getString('speicher_pfad'); if (pfad != null && pfad.isNotEmpty) { widget.downloader.setzeSpeicherPfad(pfad); setState(() => _speicherOrt = pfad.split('/').last); } else { final pf = await _standardPfad(); widget.downloader.setzeSpeicherPfad(pf); } } Future _standardPfad() async { if (Platform.isIOS) return '${(await getApplicationDocumentsDirectory()).path}/music'; final p = await SharedPreferences.getInstance(); if (p.getBool('manage_storage') == true) { final d = await getDownloadsDirectory(); if (d != null) return '${d.path}/Melo'; } final ext = await getExternalStorageDirectory(); return ext != null ? '${ext.path}/Melo' : '${(await getApplicationDocumentsDirectory()).path}/music'; } Future _ordnerDialog() async { if (Platform.isIOS) { final appDir = await getApplicationDocumentsDirectory(); final pfad = '${appDir.path}/music'; widget.downloader.setzeSpeicherPfad(pfad); setState(() => _speicherOrt = '📁 App-intern'); return; } // Android: Ordner wählen via Text-Eingabe oder vordefinierte Optionen final auswahl = await showDialog( context: context, builder: (ctx) => AlertDialog( backgroundColor: MeloTheme.dunkel1, title: const Text('Speicherort', style: TextStyle(color: Colors.white, fontSize: 16)), content: Column( mainAxisSize: MainAxisSize.min, children: [ _optionTile(ctx, '📁 Intern (App-Ordner)', 'intern', icon: Icons.phone_android), const Divider(color: MeloTheme.dunkel2), _optionTile(ctx, '⬇ Downloads/Melo', 'downloads', icon: Icons.download), const Divider(color: MeloTheme.dunkel2), _optionTile(ctx, '📂 Eigener Pfad...', 'custom', icon: Icons.folder_open), ], ), ), ); if (auswahl == null || !mounted) return; String pfad; if (auswahl == 'custom') { final ctrl = TextEditingController(); final p = await showDialog( context: context, builder: (ctx) => AlertDialog( backgroundColor: MeloTheme.dunkel1, title: const Text('Pfad eingeben', style: TextStyle(color: Colors.white, fontSize: 15)), content: TextField( controller: ctrl, autofocus: true, style: const TextStyle(color: Colors.white), decoration: InputDecoration( hintText: '/storage/emulated/0/Music/Melo', hintStyle: const TextStyle(color: Colors.grey), border: const OutlineInputBorder(), prefixIcon: const Icon(Icons.folder, color: Colors.grey), ), ), actions: [ TextButton(onPressed: () => Navigator.pop(ctx), child: const Text('Abbrechen')), TextButton(onPressed: () => Navigator.pop(ctx, ctrl.text.trim()), child: const Text('OK', style: TextStyle(color: MeloTheme.rot))), ], ), ); if (p == null || p.isEmpty) return; pfad = p; } else if (auswahl == 'intern') { pfad = await _standardPfad(); } else { final d = await getDownloadsDirectory(); pfad = d != null ? '${d.path}/Melo' : await _standardPfad(); } await Directory(pfad).create(recursive: true); widget.downloader.setzeSpeicherPfad(pfad); final prefs = await SharedPreferences.getInstance(); await prefs.setString('speicher_pfad', pfad); setState(() => _speicherOrt = pfad.split('/').last); } Widget _optionTile(BuildContext ctx, String label, String wert, {IconData? icon}) { return ListTile( leading: Icon(icon ?? Icons.folder, color: MeloTheme.rot, size: 20), title: Text(label, style: const TextStyle(color: Colors.white, fontSize: 13)), onTap: () => Navigator.pop(ctx, wert), ); } Future _startDownload() async { final url = _urlController.text.trim(); if (url.isEmpty) return; setState(() { _ladt = true; _fehler = null; _erfolg = null; }); try { final song = await widget.downloader.downloadVonUrl(url); if (!mounted) return; if (song != null) { setState(() { _ladt = false; _erfolg = '✅ "${song.titel}" heruntergeladen!'; }); widget.onSongsChanged(); } else { setState(() { _ladt = false; _fehler = widget.downloader.fehler ?? '❌ Download fehlgeschlagen'; }); } } catch (e) { MeloLogger().fehler('download', e); if (mounted) setState(() { _ladt = false; _fehler = 'Fehler: $e'; }); } } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: MeloTheme.schwarz, appBar: AppBar( backgroundColor: MeloTheme.dunkel1, title: const Row(children: [ Icon(Icons.add_circle, color: MeloTheme.rot, size: 20), SizedBox(width: 8), Text('Lied +', style: TextStyle(color: Colors.white, fontSize: 18)), ]), ), body: Padding( padding: const EdgeInsets.all(20), child: Column(children: [ GestureDetector( onTap: _ladt ? null : _ordnerDialog, child: Container( width: double.infinity, padding: const EdgeInsets.all(12), decoration: BoxDecoration(color: MeloTheme.dunkel1, borderRadius: BorderRadius.circular(12), border: Border.all(color: MeloTheme.dunkel2)), child: Row(children: [ const Icon(Icons.folder, color: MeloTheme.rot, size: 18), const SizedBox(width: 8), Expanded(child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('Speicherort', style: TextStyle(color: Colors.grey, fontSize: 11)), Text(_speicherOrt, style: const TextStyle(color: Colors.white, fontSize: 13)), ])), const Icon(Icons.chevron_right, color: Colors.grey, size: 18), ]), ), ), const SizedBox(height: 16), TextField( controller: _urlController, style: const TextStyle(color: Colors.white), decoration: InputDecoration( hintText: 'YouTube / SoundCloud URL...', hintStyle: const TextStyle(color: Colors.grey), filled: true, fillColor: MeloTheme.dunkel1, border: OutlineInputBorder(borderRadius: BorderRadius.circular(12), borderSide: const BorderSide(color: MeloTheme.dunkel2)), prefixIcon: const Icon(Icons.link, color: Colors.grey), ), ), const SizedBox(height: 12), SizedBox( width: double.infinity, child: ElevatedButton.icon( style: ElevatedButton.styleFrom(backgroundColor: MeloTheme.rot, padding: const EdgeInsets.symmetric(vertical: 14), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12))), onPressed: _ladt ? null : _startDownload, icon: _ladt ? const SizedBox(width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2, color: Colors.white)) : const Icon(Icons.download, color: Colors.white), label: Text(_ladt ? 'Lädt...' : 'Download', style: const TextStyle(color: Colors.white, fontSize: 15)), ), ), const SizedBox(height: 12), if (_fehler != null) Padding(padding: const EdgeInsets.only(top: 8), child: Text(_fehler!, style: const TextStyle(color: Colors.red, fontSize: 13))), if (_erfolg != null) Padding(padding: const EdgeInsets.only(top: 8), child: Text(_erfolg!, style: const TextStyle(color: Colors.green, fontSize: 13))), ]), ), ); } }