v2.32 — Defekte Musik erkennen (Magic Bytes, ffprobe, DB-Flag, UI)

This commit is contained in:
Dustin
2026-08-01 16:40:42 +02:00
parent 4a05c76199
commit 2d4c7c8b98
9 changed files with 352 additions and 4 deletions
+128 -1
View File
@@ -25,6 +25,8 @@ class _CloudScreenState extends State<CloudScreen> {
int _syncIntervall = 6;
Timer? _syncTimer;
String _letzterSync = 'Nie';
List<Map> _korrupteSongs = [];
bool _ladtKorrupt = false;
@override
void initState() {
@@ -91,6 +93,18 @@ class _CloudScreenState extends State<CloudScreen> {
});
}
Future<void> _ladeKorrupteSongs() async {
setState(() => _ladtKorrupt = true);
try {
final corrupted = await widget.cloud.getCorrupted();
if (mounted) setState(() => _korrupteSongs = corrupted);
} catch (e) {
MeloLogger().fehler('cloud_corrupted_laden', e);
} finally {
if (mounted) setState(() => _ladtKorrupt = false);
}
}
Future<void> _upload() async {
setState(() => _ladt = true);
_setzeStatus('Suche lokale Songs...');
@@ -284,7 +298,14 @@ class _CloudScreenState extends State<CloudScreen> {
),
const SizedBox(height: 8),
_intervallAuswahl(),
const SizedBox(height: 12),
const SizedBox(height: 20),
// ─── Korrupte Songs (vom Server) ───
_sektionsHeader('⚠️ Defekte Musik (Server)'),
const SizedBox(height: 8),
_korrupteSektion(),
const SizedBox(height: 20),
// Letzter Sync
Container(
@@ -483,6 +504,112 @@ class _CloudScreenState extends State<CloudScreen> {
),
);
}
Widget _korrupteSektion() {
return Container(
width: double.infinity,
padding: const EdgeInsets.all(14),
decoration: BoxDecoration(
color: MeloTheme.dunkel1,
borderRadius: BorderRadius.circular(14),
border: Border.all(color: MeloTheme.dunkel2),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Button zum Abrufen
Row(
children: [
Expanded(
child: GestureDetector(
onTap: _ladtKorrupt ? null : _ladeKorrupteSongs,
child: Container(
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 14),
decoration: BoxDecoration(
color: MeloTheme.rot.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(10),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (_ladtKorrupt)
const SizedBox(
width: 14, height: 14,
child: CircularProgressIndicator(
color: MeloTheme.rot, strokeWidth: 2,
),
)
else
const Icon(Icons.warning_amber_rounded, color: MeloTheme.rot, size: 16),
const SizedBox(width: 8),
Text(
_ladtKorrupt ? 'Prüfe...' : 'Auf defekte Musik prüfen',
style: const TextStyle(
color: MeloTheme.rot, fontSize: 13, fontWeight: FontWeight.w600,
),
),
],
),
),
),
),
],
),
// Ergebnisliste
if (_korrupteSongs.isNotEmpty) ...[
const SizedBox(height: 12),
const Divider(color: MeloTheme.dunkel2, height: 1),
const SizedBox(height: 8),
Text(
'${_korrupteSongs.length} defekte Songs gefunden:',
style: const TextStyle(
color: Color(0xFFEF9A9A), fontSize: 12, fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 8),
..._korrupteSongs.map((s) => Padding(
padding: const EdgeInsets.only(bottom: 6),
child: Row(
children: [
const Text('⚠️', style: TextStyle(fontSize: 13)),
const SizedBox(width: 8),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
s['title']?.toString() ?? 'Unbekannt',
style: const TextStyle(
color: Colors.white70, fontSize: 12,
decoration: TextDecoration.lineThrough,
),
),
if (s['reason'] != null)
Text(
s['reason'].toString(),
style: const TextStyle(
color: MeloTheme.textSekundaer, fontSize: 10,
),
),
],
),
),
],
),
)),
] else if (!_ladtKorrupt && _korrupteSongs.isEmpty)
const Padding(
padding: EdgeInsets.only(top: 8),
child: Text(
'Keine defekten Songs auf dem Server',
style: TextStyle(color: Color(0xFFA5D6A7), fontSize: 12),
),
),
],
),
);
}
}
class _IntervallOption {