This repository has been archived on 2026-08-19. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
melo-app/CODE_REVIEW.md

5.1 KiB
Raw Permalink Blame History

🟢 Melo App — Aktuelles Code-Review (v2.5)

Geprüft: 24.07.2026 | Projekt: ~/Projects/melo_app/ | Dustin (Baka) — Kiel Prinzip: Ponytail — minimaler Code, maximale Wirkung, max 500 Zeilen pro Datei Gesamt-Score: A- (Hervorragend verbessert!)


Status der Altschulden (Review-Vergleich)

Alle kritischen Probleme aus dem vorherigen Review wurden vollständig und sauber gelöst:

  • CRIT-1 (Memory Leak im MiniPlayer): StreamSubscriptions werden jetzt ordnungsgemäß in dispose() gecancelled.
  • CRIT-2 (Null-Crash im Metadaten-Editor): widget.song.id! wurde durch ein sicheres ID-Null-Guard ersetzt.
  • CRIT-3 (Dauer-Sekunden = 0): Wird jetzt beim Scannen über den Player ermittelt. (Siehe Performance für Optimierungspotenzial).
  • CRIT-4 (Verlaufs-Flut): positionAktualisieren führt jetzt saubere Updates/Upserts statt endloser Inserts durch.
  • CRIT-5 (ErrorBoundary-Deko): Der tote AppWrapper und FlutterErrorBoundary in main.dart wurden komplett entfernt (Ponytail-Prinzip!).

📐 Five-Axis Quality Gate

1. CORRECTNESS (Korrektheits-Check) — Score: A-

  • Sicherheits-Guards: Hervorragende null-safety Guards im Metadaten-Editor und beim Wiedergabestatus.
  • Division durch Null (Download): In download_service.dart:103 bei _fortschritt = downloaded / total; besteht ein minimales theoretisches Risiko eines NaN (Division durch Null), falls total (audio.size.totalBytes) jemals 0 zurückgeben sollte.
    • Empfehlung: Ein kurzer Ternary Guard: _fortschritt = total > 0 ? downloaded / total : 0.0;
  • Substring-Range: p.erstelltAm.substring(0, 10) in playlist_sheet.dart:103 ist sicher, da erstelltAm durch das ISO-Format standardmäßig >= 19 Zeichen lang ist.

2. READABILITY (Lesbarkeit) — Score: A

  • Konsistente Namensgebung: Großartiger, verständlicher Code. Deutsche Variablennamen (_aktiverTab, _ladeSongs()) werden konsistent und clean durchgezogen.
  • Kein Code-Spam: Die Klassen sind kompakt, sauber formatiert und verzichten auf unnötige Schachtelungen.

3. ARCHITECTURE (Architektur & Struktur) — Score: B+

  • dynamic vm Anti-Pattern: In playlist_sheet.dart und navidrome_browser.dart wird final dynamic vm verwendet. Das deaktiviert jegliche Typprüfung, Autovervollständigung und birgt das Risiko von Laufzeitfehlern, falls sich ViewModel-Methoden ändern.
    • Empfehlung: Ersetze dynamic vm durch den konkreten Typ final MeloHomeViewModel vm.
  • Zukünftige DB-Migrationen: DbHelper.db initialisiert die SQLite-Datenbank mit version: 1 ohne onUpgrade-Callback. Wenn du später Tabellen anpasst, crasht die App bei bestehenden Nutzern beim Start.
    • Empfehlung: Bereits jetzt eine leere onUpgrade Struktur im openDatabase vorsehen.
  • Redundanter Aufruf: In MeloHomeViewModel.ladeSongs() wird tagCounts = _berechneTagCounts(); aufgerufen, während tags noch ein leeres Array [] ist. Erst danach wird await ladeTags() aufgerufen, welches _berechneTagCounts() erneut aufruft. Der erste Aufruf ist also redundant.

4. PERFORMANCE (Laufzeit & Ressourcen) — Score: B

  • Granularer Rebuild (Großartig!): Die Implementierung des MiniPlayer ist perfekt gelöst. Er lauscht direkt auf die Streams des Players und aktualisiert seinen State lokal per setState. Dadurch wird verhindert, dass bei jedem Millisekunden-Update des Fortschrittsbalkens der gesamte Home-Bildschirm (mit Statistiken, Listen und Covern) neu gerendert wird!
  • 🚨 Der Scanner-Flaschenhals: In lib/services/musik_scanner.dart wird in _ermittleDauer(pfad) für jeden einzelnen gefundenen Song ein komplett neuer AudioPlayer instanziiert, die Datei geöffnet, die Dauer gelesen und der Player wieder disposed.
    • Problem: Wenn ein Ordner 200 Songs enthält, wird 200-mal nacheinander ein nativer Player erzeugt und zerstört. Das blockiert den Scanvorgang extrem, zieht viel Akku und kann auf manchen Systemen zu Abstürzen oder "Platform Channel Exception"-Fehlern (Erschöpfung der Audio-Player-Kanäle) führen.
    • Empfehlung: Entweder eine extrem leichtgewichtige Metadata-Bibliothek (flutter_media_metadata) nutzen, oder eine einzige AudioPlayer-Instanz für den gesamten Scanvorgang wiederverwenden, anstatt sie in der Schleife ständig neu zu erstellen.

5. SECURITY (Sicherheit) — Score: A

  • Berechtigungen: Vorbildliche Handhabung von Android Scoped Storage Permissions über Permission.audio statt der veralteten Permission.storage (deprecating ab Android 13).

🛠 Top 3 Quick Wins

  1. Typsicherheit im UI: Ändere final dynamic vm in playlist_sheet.dart und navidrome_browser.dart zu final MeloHomeViewModel vm. Das gibt dir volles Autocomplete und Compile-Safety.
  2. Scanner beschleunigen: Instanziiere den AudioPlayer für die Dauer-Ermittlung einmalig außerhalb der Schleife im MusikScanner und nutze ihn für alle Dateien, statt ihn pro Song neu zu erstellen und zu disposen.
  3. VM-Cleanup: Entferne den redundanten Aufruf von tagCounts = _berechneTagCounts(); aus Zeile 78 in melo_home_viewmodel.dart.