Files
Melo/.ui-design/reviews/melo_vollwertigkeit_20260823.md
T
Hermes (Server)andClaude Opus 5 e6d5f1c9ee Fuenf P0-Fehler behoben: Benachrichtigung, Offline, Cover, Warteschlange
Ergebnis einer Durchsicht der App gegen den Massstab "Apple Music".
Alle fuenf Punkte waren keine fehlenden Funktionen, sondern Versprechen,
die die Oberflaeche gab und der Code nicht hielt.

- POST_NOTIFICATIONS fehlte im Manifest. Auf Android 13+ blieb die
  Wiedergabe-Benachrichtigung dadurch unsichtbar. Das Recht wird erst
  erfragt, wenn wirklich ein Titel laeuft.
- Der Offline-Schalter wurde nirgends gelesen. Er greift jetzt an allen
  drei Wegen in die Warteschlange; uebersprungene Titel werden benannt.
- CoverImage kannte nur file://, und der Server-Browser gab die
  Cover-Adresse gar nicht erst mit. Server-Titel waren deshalb immer ein
  graues Notensymbol.
- Warteschlange entfernen/umsortieren baute die ganze Queue neu auf:
  hoerbarer Aussetzer und doppelte Wiedergabe-Zaehlung. Jetzt mutiert nur
  der betroffene Eintrag, die Buchfuehrung steht vor dem Player.
- Das Herz bei Server-Titeln legte einen Favoriten mit leerer Kennung an,
  der nie in der Liste auftauchte. Es ist jetzt ausgegraut.

Nachgebessert aus dem Code-Review: Offline-Meldung an die Stelle geholt,
wo sie greifen kann; Queue-Buchfuehrung vor den Player gezogen;
Fehlerpfad fuer die Berechtigungs-Abfrage ergaenzt.

360 Tests gruen (vorher 328), flutter analyze ohne Befund, Release-APK
gebaut und POST_NOTIFICATIONS darin nachgeprueft.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013xAHJTJM6UUqmjUgk1PUEd
2026-08-23 18:34:26 +02:00

362 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Design- & Feature-Review: Melo vs. Apple Music / Spotify
**Review-ID:** melo_vollwertigkeit_20260823
**Datum:** 2026-08-23
**Umfang:** gesamte App (`lib/`, 56 Dateien, 14.721 Zeilen), Android-Manifest, Referenz-Bilder
**Fokus:** Visual · Usability · Funktionsumfang · Code
**Werkzeuge:** ui-ux-pro-max (design-system + flutter stack + pro-rules), ui-design:design-review
**Verifizierter Ist-Zustand:** `flutter analyze`*No issues found*. `flutter test`*328 bestanden, 1 übersprungen* (der bekannte Hänger aus BACKLOG.md).
---
## Summary
Melo ist technisch überdurchschnittlich sauber: echtes Design-Token-System, WCAG-geprüfte
Textfarben, Tombstone-fähiges Schema ab Tag 1, hohe Testabdeckung, deutschsprachige
Erklär-Kommentare an genau den Stellen, wo früher Bugs saßen. Das ist deutlich besser als
der Durchschnitt eines Hobby-Projekts.
Als **vollwertige Musik-App im Sinne von Apple Music ist sie es aber noch nicht.** Es fehlen
nicht Details, sondern drei tragende Säulen: **Alben als Browse-Achse**, **echtes Offline-
Management** und **Cover-Art für Server-Titel**. Dazu kommen zwei stille Fehler, die man
der App nicht ansieht: der Offline-Schalter tut nichts, und ohne `POST_NOTIFICATIONS`
erscheint auf Android 13+ keine Wiedergabe-Benachrichtigung.
**Gefundene Punkte:** 26 → 5 kritisch · 10 groß · 7 klein · 4 Vorschläge
> **Stand 2026-08-23, nach der Umsetzung:** Die fünf P0-Punkte (K1K5) sind
> behoben, siehe CHANGELOG. G9 und G10 kamen bei der Umsetzung dazu und
> sind offen.
---
## Kritische Punkte (P0)
### K1 — Offline-Modus ist ein toter Schalter
**Ort:** `lib/services/offline_mode.dart` · `lib/settings/settings_screen.dart:190`
**Kategorie:** Usability / Korrektheit
`OfflineMode` speichert ein Bool in den SharedPreferences und ruft `notifyListeners()`.
Das war's. Verifiziert per Volltextsuche: **kein einziger Leser** außerhalb von
`main.dart` (Registrierung) und dem Settings-Schalter selbst. `MeloAudioHandler`,
`NavidromeService` und `SyncService` fragen ihn nie ab.
**Wirkung:** Der Nutzer schaltet "Nur gecachte Lieder abspielen" ein, die App streamt
trotzdem und verbraucht Mobilfunkdaten. Ein Versprechen, das die UI gibt und der Code
bricht.
**Empfehlung:** `OfflineMode` in `loadPlaylist` auslesen. Ist er an, nur Titel mit
Cache-Treffer oder lokalem Pfad in die Queue nehmen und die übersprungenen sichtbar
machen ("3 Titel übersprungen — nicht offline verfügbar").
---
### K2 — Keine `POST_NOTIFICATIONS`-Berechtigung
**Ort:** `android/app/src/main/AndroidManifest.xml`
**Kategorie:** Plattform
Verifiziert im **gemergten** Manifest
(`build/app/intermediates/merged_manifests/release/.../AndroidManifest.xml`):
`POST_NOTIFICATIONS` ist nicht dabei. `targetSdk` folgt Flutter (≥ 33).
**Wirkung:** Auf Android 13+ zeigt das System die Media-Notification erst nach
erteilter Laufzeit-Berechtigung. Ohne sie fehlt die zentrale Bedienfläche einer
Musik-App im Alltag. Der Vordergrunddienst läuft, aber unsichtbar.
**Empfehlung:** Permission ins Manifest, beim ersten Start der Wiedergabe abfragen
(`permission_handler` ist bereits als Abhängigkeit da).
---
### K3 — Server-Titel haben nie ein Coverbild
**Ort:** `lib/shared/cover.dart:38` · `lib/downloads/downloads_screen.dart:309`
**Kategorie:** Visual
`CoverImage` rendert **ausschließlich** `artUri.scheme == 'file'`. Für alles andere
kommt der Noten-Platzhalter. Navidrome-Titel bekommen in `_playAlbum`/`_playArtist`
gar kein `artUri` mitgegeben — obwohl `NavidromeService.coverUrl` (Zeile 265) existiert
und `SubsonicAlbum.coverId` geparst wird.
**Wirkung:** Jeder Server-Titel ist in Liste, Mini-Player, Vollbild-Player, Notification
und Sperrbildschirm ein graues Notensymbol. Das ist der augenfälligste Unterschied zu
Apple Music — dort trägt das Cover die gesamte visuelle Identität.
**Empfehlung:** `CoverImage` um `Image.network` für http/https erweitern (mit
`cacheWidth`, Fehler-Fallback auf den Platzhalter), und in beiden `_play*`-Methoden
`artUri: _nav.coverUrl(s.coverId)` setzen. Bild-Cache lokal ablegen, damit es offline
bleibt.
---
### K4 — Alben fehlen als Browse-Achse
**Ort:** `lib/library/song_grouping.dart` · `lib/library/my_music_screen.dart:88`
**Kategorie:** Funktionsumfang
`Songs.album` ist eine Textspalte, aber es gibt weder eine Alben-Liste noch einen
Album-Detail-Screen. `song_grouping.dart` kann nur `groupByArtist`. Die Unterreiter
heißen **Lieder / Kategorie / Künstler** — im Referenz-Screenshot
(`ui-referenz/bugs/img_2d5761551808.jpg`, das ist Melo selbst) stand dort noch
**Songs / Künstler / Alben**. Die Achse ist also verlorengegangen.
**Wirkung:** Album ist neben Playlist die wichtigste Einheit, in der Menschen Musik
denken. Ohne sie ist "Bibliothek" eine flache Titelliste — brauchbar bei 200 Titeln,
unbrauchbar bei 5.000.
**Empfehlung:** `groupByAlbum` (analog zu `groupByArtist`, existierende `_groupBy`-
Hilfsfunktion nutzt man mit), vierter Unterreiter, Album-Screen mit großem Cover,
Künstler, Jahr, Titelzahl, Gesamtdauer und "Abspielen / Zufällig".
---
### K5 — Warteschlange neu ordnen startet die Wiedergabe neu
**Ort:** `lib/player/queue_screen.dart:87,103` · `lib/player/audio_handler.dart:169`
**Kategorie:** Usability / Korrektheit
Der Kommentar im Code ist ehrlich: der Handler bietet keine Live-Mutation, also ruft
jedes Entfernen und jedes Verschieben `loadPlaylist()` auf. Das führt
`_player.setAudioSources(...)` + `play()` + `seek()` aus.
Drei Folgen:
1. **Hörbarer Aussetzer** bei jeder Queue-Änderung — bei Apple Music passiert das lautlos.
2. `loadPlaylist` setzt `_lastCountedIndex = null` (Zeile 173) → der laufende Titel wird
**erneut als Wiedergabe gezählt**. Die Sortierung "Wie oft abgespielt" wird durch
Queue-Bedienung verfälscht.
3. Bei Server-Titeln werden alle Cache-Treffer neu ermittelt (`await` in der Schleife).
**Empfehlung:** `removeQueueItem`/`insertQueueItem` auf `_player.removeAudioSourceAt` /
`moveAudioSource` abbilden. `just_audio` kann das ohne Neuaufbau.
---
## Große Punkte (P1)
### G1 — Suche findet nur lokale Titel, nur flach
**Ort:** `lib/library/search_screen.dart` (59 Zeilen)
`db.searchSongs()` per LIKE über Titel/Künstler/Album. Kein Server (`search3.view` wird
nirgends aufgerufen), keine Playlisten, keine Kategorien, keine Gruppierung der Treffer
nach Typ, keine letzten Suchen, keine Vorschläge, kein Entprellen. Apple Music gruppiert
Ergebnisse in Titel/Alben/Künstler/Playlists und zeigt bei leerem Feld die Historie.
Der ganze Tab ist heute ein Textfeld über einer Liste.
### G2 — Navidrome ist im Download-Tab versteckt
**Ort:** `lib/downloads/downloads_screen.dart:56`
Der komplette Server-Browser ist ein Unterreiter von "Download". Ein Nutzer, der seine
Server-Bibliothek hören will, sucht sie nicht unter "Download". Im Referenz-Screenshot
hieß der Tab noch "Online" — treffender.
Dazu: Tippen auf ein Album **spielt sofort ab**. Es gibt keinen Album-Screen, keine
Titelliste, keine Möglichkeit, einen einzelnen Server-Titel zu wählen. Nur 50 Alben,
kein Nachladen, keine Server-Suche.
### G3 — Server-Titel sind Bürger zweiter Klasse
**Ort:** `lib/library/song_media.dart` vs. `lib/downloads/downloads_screen.dart:309`
Ein `MediaItem` vom Server trägt nur `navidromeId`**kein** `songId`. Damit gilt für
Server-Titel: kein Favorit, keine Playlist-Zuordnung, kein lokaler Wiedergabezähler,
keine Kategorie, kein Cover, kein Eintrag in der Historie.
**Konkreter Fehler daraus:** `now_playing_screen.dart:45` gibt
`FavoriteButton(songId: item.extras?['songId'] ?? '')` — bei Server-Titeln also den
**leeren String**. `FavoriteButton` prüft nicht darauf, `toggleFavorite('')` legt eine
Favoriten-Zeile mit leerer ID an. Das Herz füllt sich, in der Favoritenliste (INNER JOIN
auf `songs`) taucht nichts auf. Falsche Rückmeldung an den Nutzer.
### G4 — Kein gezielter Offline-Download
**Ort:** `lib/services/cache_manager.dart` · `lib/player/audio_handler.dart:203`
Gecacht wird nur, was zufällig abgespielt wurde. Es gibt kein "Album offline verfügbar
machen", keine Anzeige, welche Titel offline sind, kein Verwalten pro Titel.
`CacheManager` hat außerdem **keine Größenbegrenzung und keine Verdrängung** — nur
"alles löschen". Der Cache wächst unbegrenzt. Alle Dateien werden `.mp3` benannt,
unabhängig vom tatsächlichen Codec (Navidrome liefert oft Opus/FLAC).
### G5 — Kein "läuft gerade"-Zustand in der Liste
**Ort:** `lib/library/song_list.dart:157`
Die Referenz-UI zeigt den laufenden Titel farbig hervorgehoben mit animierten Balken.
Melos `SongList` hat keinerlei Bezug zum `mediaItem`-Stream. Der Nutzer scrollt durch die
Liste und sieht nicht, wo er gerade ist.
### G6 — Zwei verschiedene Rot-Töne
**Ort:** 10 Vorkommen von `Colors.redAccent` (#FF5252), meist in `settings_screen.dart`
und `downloads_screen.dart`
Die Marke ist `MeloTheme.red` = #C0392B (gedecktes Ziegelrot). `Colors.redAccent` ist ein
grelles Signalrot. Beide stehen im selben Screen nebeneinander. Insgesamt **58
hartcodierte `Colors.*`-Werte** außerhalb des Themes, 18 davon allein in den
Einstellungen — die sind visuell der schwächste Screen der App.
### G7 — Emoji als Icon
**Ort:** `downloads_screen.dart:234,247` (📀 Alben / 🎤 Künstler),
`settings_screen.dart:190` (📴 Offline-Modus), `now_playing_screen.dart:362` (📝 Songtext)
Verstößt gegen die erste Regel der Pre-Delivery-Checkliste von ui-ux-pro-max: Emoji
rendern je nach Hersteller-Font unterschiedlich, lassen sich nicht einfärben, folgen
keinem Design-Token und sind für Screenreader Unsinn. Material-Icons sind vorhanden
(`Icons.album`, `Icons.mic`, `Icons.cloud_off`, `Icons.lyrics`).
### G8 — Songtext ist ein statischer Textblock
**Ort:** `lib/player/now_playing_screen.dart:309`
Der Text wird als eine Wand angezeigt. Kein Zeilen-Sync (LRC), kein Mitlaufen, kein
Antippen zum Springen. Navidromes `getLyricsBySongId` liefert synchronisierte Texte.
Das ist bei Apple Music eine der meistgenutzten Funktionen.
---
### G9 — Nach `stop()` merkt sich die App keine Positionen mehr *(bei der P0-Umsetzung gefunden)*
**Ort:** `lib/player/audio_handler.dart:258` (`stop`)
**Kategorie:** Korrektheit · **Status:** nicht behoben, außerhalb des P0-Auftrags
`stop()` ruft `_positionRecordTimer.cancel()`. Der Timer ist `Timer.periodic`
und wird nur **einmal im Konstruktor** angelegt — einmal abgebrochen, kommt er
für den Rest der App-Sitzung nicht zurück.
`stop()` löst nicht nur der Nutzer aus: das System ruft es beim Wegwischen der
Benachrichtigung und über die Stop-Aktion auf. Danach speichert die App keine
Wiedergabepositionen mehr und scrobbelt nicht mehr zum Server — bis zum
Neustart, und ohne jeden Hinweis. „Fortsetzen an alter Stelle" hört damit
still auf zu funktionieren.
**Empfehlung:** Den Timer in `stop()` nicht abbrechen, sondern in der Callback
prüfen (`if (!_player.playing) return;` steht bereits drin — der Abbruch ist
also gar nicht nötig). Abbrechen gehört allein in `dispose()`.
**Vorbestehend**, nicht durch die P0-Änderungen entstanden: der alte
`QueueScreen` rief in derselben Lage ebenfalls `handler.stop()` auf.
---
### G10 — Server-Cover haben keinen dauerhaften Zwischenspeicher *(Folge der K3-Umsetzung)*
**Ort:** `lib/shared/cover.dart:55`
**Kategorie:** Performance · **Status:** offen, bewusst nicht in P0
`Image.network` legt nur im Arbeitsspeicher ab (Flutters `ImageCache`, ~100 MB,
beim Beenden weg). Beim nächsten Kaltstart fragt jede sichtbare Zeile ihr Cover
erneut beim Server an. Außerdem laufen diese Anfragen auch im Offline-Modus —
sie schlagen dann fehl und fallen auf den Platzhalter zurück, kosten aber
Versuche.
Ein dauerhafter Cache bräuchte entweder `cached_network_image` als neue
Abhängigkeit oder eine Erweiterung des vorhandenen `CacheManager` auf Bilder.
Beides ist eine Entscheidung, keine Fehlerbehebung — deshalb nicht im P0-Fix.
Der Unterschied zu vorher bleibt trotzdem groß: bisher gab es **überhaupt kein**
Server-Cover.
---
## Kleine Punkte (P2)
| # | Punkt | Ort |
|---|---|---|
| P1 | AppBar der Einstellungen heißt **"Settings"** — einziges englisches Wort in einer deutschen App | `settings_screen.dart:65` |
| P2 | Kein `Hero`-Übergang Mini-Player → Vollbild (0 Treffer in `lib/`). Der Wechsel springt, statt das Cover wandern zu lassen | `mini_player.dart:70` |
| P3 | Kein Wischen am Mini-Player (nach unten = schließen, seitlich = nächster Titel) | `mini_player.dart` |
| P4 | Künstlerliste ist eine nackte `ListTile`-Liste ohne Bilder; kein Album-Zwischenschritt | `artist_list.dart:31` |
| P5 | Keine Reduced-Motion-Unterstützung (0 Treffer für `disableAnimations`), obwohl `MeloMotion` sauber getokent ist | `theme.dart:41` |
| P6 | Keine Querformat-/Tablet-Anpassung (`LayoutBuilder` nur in `cover.dart`, `MediaQuery.size` nur im Equalizer) | app-weit |
| P7 | Kein Alphabet-Schnellscroller und keine Mehrfachauswahl in langen Listen | `song_list.dart` |
---
## Vorschläge (P3)
- **V1 — Farbe aus dem Cover ziehen.** Apple Music und Spotify färben den Player nach dem
Albumcover. In Flutter mit `PaletteGenerator` + Verlauf hinter dem Cover. Größter
optischer Sprung pro Zeile Code.
- **V2 — Eigene Schrift.** Die App nutzt System-Roboto. Die ui-ux-pro-max-Abfrage für
"music entertainment" schlägt Righteous/Poppins vor; für Schwarz/Rot passt eher eine
kräftige Grotesk (Outfit, Sora) für Überschriften bei Roboto/Inter im Fließtext.
- **V3 — YouTube-Share-Intent.** Aktuell muss man die URL kopieren und einfügen. Ein
`ACTION_SEND`-Intent-Filter im Manifest macht "Teilen → Melo" möglich. Sehr kleine
Änderung, spürbarer Alltagsgewinn.
- **V4 — Android Auto / Assistant.** Der `MediaBrowserService` ist im Manifest deklariert,
aber `MeloAudioHandler` überschreibt `getChildren`/`getMediaItem` nicht — Browsen im Auto
funktioniert also nicht. Kein Widget, keine Wear-Unterstützung.
---
## Was gut ist (nicht ändern)
- **Design-Token-System** (`theme.dart`): `MeloSpace`, `MeloRadius`, `MeloMotion` mit
begründeten Werten. Die Textfarben sind nicht geschätzt, sondern per
`theme_kontrast_test.dart` gegen 4,5:1 nachgerechnet. Das machen wenige.
- **Haarlinie statt Schatten** auf Schwarz — richtige Entscheidung für OLED, deckt sich mit
der "Dark Mode (OLED)"-Empfehlung des Style-Katalogs.
- **Datenmodell**: UUID + `updatedAtMs` + `deleted`-Tombstone ab Schema 1, 9 saubere
Migrationen. Sync war von Anfang an mitgedacht statt nachgerüstet.
- **Reine Funktionen ausgelagert** (`shouldResumeAt`, `playNextIndex`, `reorderQueue`,
`planeSync`, `newPlayingIndex`) — deshalb 328 Tests ohne Emulator.
- **Kommentare erklären das Warum**, oft mit dem konkreten Bug, der dahinterstand
(`navidromeIdOf`, `cacheSchluessel`, `loadPlaylist`). Genau die Stellen aus
`ui-referenz/bugs/` sind so dokumentiert.
- **Tooltips überall** an Icon-Buttons → in Flutter automatisch Semantics-Label.
---
## Priorisierter Plan
### P0 — bevor irgendetwas Neues gebaut wird
1. `POST_NOTIFICATIONS` ins Manifest + Laufzeit-Abfrage *(K2, ~1 h)*
2. Offline-Modus wirklich verdrahten oder den Schalter entfernen *(K1, ~3 h)*
3. `CoverImage` für http + `artUri` bei Server-Titeln setzen *(K3, ~3 h)*
4. Queue ohne Neuladen mutieren, Doppelzählung beenden *(K5, ~4 h)*
5. Leere `songId` in `FavoriteButton` abfangen *(G3-Teil, ~30 min)*
### P1 — das macht sie "vollwertig"
6. Alben-Achse: `groupByAlbum`, vierter Unterreiter, Album-Screen *(K4, ~1 Tag)*
7. Suche umbauen: nach Typ gruppiert, Server einbeziehen, letzte Suchen *(G1, ~1,5 Tage)*
8. Server-Bereich aus "Download" lösen → eigener Tab "Online" mit Album-Detail *(G2, ~1,5 Tage)*
9. Offline-Download pro Album/Playlist + Cache-Grenze mit LRU *(G4, ~1,5 Tage)*
10. "Läuft gerade"-Markierung in allen Listen *(G5, ~3 h)*
### P2 — Politur, die man sofort sieht
11. `Colors.redAccent``MeloTheme.red`, Emoji → Material-Icons, "Settings" → "Einstellungen" *(G6, G7, P1 — zusammen ~3 h)*
12. Hero-Übergang + Wischgesten am Mini-Player *(P2, P3, ~4 h)*
13. Synchronisierter Songtext (LRC) *(G8, ~1 Tag)*
14. Künstler- und Kategorieliste visuell aufwerten *(P4, ~4 h)*
15. Reduced-Motion + Querformat *(P5, P6, ~4 h)*
### P3 — danach
16. Cover-Farbe im Player *(V1)*
17. Eigene Schrift *(V2)*
18. YouTube-Share-Intent *(V3)*
19. Android Auto: `getChildren` implementieren *(V4)*
---
## Feature-Matrix gegen Apple Music
| Bereich | Apple Music | Melo | Bewertung |
|---|---|---|---|
| Wiedergabe, Hintergrund, Sperrbildschirm | ✅ | ✅ | **da** (Notification-Permission fehlt → K2) |
| Warteschlange ansehen/umordnen | ✅ | ✅ | **schwach** — Neuladen bei jeder Änderung |
| Als Nächstes / Ans Ende | ✅ | ✅ | **da** |
| Shuffle & Repeat | ✅ | ✅ | **da** |
| Sleep-Timer | ✅ | ✅ | **da** (Melo besser als Apple Music) |
| Equalizer | ⚠️ nur System | ✅ 5-Band + Bass + Virtualizer | **besser als Apple Music** |
| Lautstärke-Angleich | ✅ | ✅ ReplayGain | **da** |
| Fortsetzen an alter Stelle | ✅ | ✅ lokal + Server-Bookmark | **da** |
| Favoriten | ✅ | ✅ | **da**, aber nicht für Server-Titel |
| Playlisten anlegen/ordnen | ✅ | ✅ | **da** |
| Alben durchsuchen | ✅ | ❌ | **fehlt** |
| Künstler-Seite mit Alben | ✅ | ⚠️ nackte Titelliste | **schwach** |
| Suche | ✅ typgruppiert, serverweit | ⚠️ lokal, flach | **schwach** |
| Songtext | ✅ zeilensynchron | ⚠️ statischer Block | **schwach** |
| Offline verfügbar machen | ✅ gezielt | ⚠️ nur Zufalls-Cache | **schwach** |
| Cover-Art | ✅ | ⚠️ nur lokale Dateien | **schwach** |
| Geräte-Sync der Bibliothek | ✅ iCloud | ✅ Melo-Cloud + Tombstones | **da** |
| Scrobble / Wiedergabestatistik | ✅ | ✅ lokal + Subsonic | **da** |
| Musikerkennung (Shazam) | ✅ | ✅ ACRCloud | **da** |
| YouTube-Import | ❌ | ✅ | **Alleinstellung** |
| Kategorien / eigene Tags | ❌ | ✅ | **Alleinstellung** |
| Empfehlungen, Radio, Charts | ✅ | ❌ | **fehlt** (bewusst? Melo hat keinen Katalog) |
| Teilen | ✅ | ❌ | **fehlt** |
| Homescreen-Widget | ✅ | ❌ | **fehlt** |
| Android Auto | ✅ | ❌ | **fehlt** (Service da, Browsing nicht) |
| Cast / Sonos | ✅ | ❌ | **fehlt** |
| Crossfade / Gapless | ✅ | ❌ | **fehlt** |
**Zählung:** 13 × da · 7 × schwach · 8 × fehlt · 3 × besser als Apple Music
---
_Erzeugt mit ui-ux-pro-max 2.13.0 (design-system, --stack flutter, pro-rules) und
ui-design:design-review. Alle Code-Stellen im Repo verifiziert, `flutter analyze` und
`flutter test` zum Review-Zeitpunkt ausgeführt._