Server-User (Dustin, Baka, Tinker) melden sich beim Öffnen des YouTube-Bereichs automatisch im Hintergrund mit ihren Navidrome- Zugangsdaten beim Baka-Konto an (BakaAuth.autoAnmelden) — die manuelle Anmeldung bleibt nur für Gäste sichtbar. Schlägt die Auto-Anmeldung fehl, gibt es einen Rückfallweg zur manuellen Anmeldung, statt den User auszusperren. Login-Buttons vergrößert. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CcDiyJdVRqh1TtJk5JiabX
1491 lines
91 KiB
Markdown
1491 lines
91 KiB
Markdown
# Changelog
|
||
|
||
Alle nennenswerten Änderungen an diesem Projekt werden hier dokumentiert.
|
||
Format angelehnt an [Keep a Changelog](https://keepachangelog.com/de/1.0.0/).
|
||
|
||
## [Unreleased]
|
||
|
||
### 📺🔑 YouTube-Tab: Server-User brauchen keine eigene Baka-Anmeldung mehr (2026-08-26)
|
||
|
||
- 🔑 **Server-User (Dustin, Baka, Tinker) sehen den Baka-Anmelde-Schritt nicht
|
||
mehr.** Bisher verlangte der YouTube-Downloader/die YT-Suche IMMER eine
|
||
eigene, separate Anmeldung am Baka-Konto — unabhängig davon, ob man schon
|
||
am Melo-Server angemeldet war. Neu: Wer mit dem Melo-Server verbunden ist
|
||
(`NavidromeService.istVerbunden`), meldet sich beim Öffnen des
|
||
YouTube-Bereichs automatisch im Hintergrund mit denselben Zugangsdaten
|
||
beim Baka-Konto an (`BakaAuth.autoAnmelden`, neu in `baka_auth.dart`) —
|
||
kein Dialog, kein Warten. Voraussetzung: Navidrome- und Baka-Konto teilen
|
||
sich Benutzername + Passwort (so bei Dustin/Baka/Tinker der Fall).
|
||
Schlägt die Hintergrund-Anmeldung fehl (z. B. abweichendes Passwort),
|
||
bekommt der Server-User den bisherigen manuellen Anmelde-Weg als
|
||
Rückfalloption zurück — sonst gäbe es keinen Weg mehr zu `_AnmeldeDialog`,
|
||
das war ein im @code-review-Fund entdeckter Aussperr-Bug (siehe
|
||
`pruefeServerUser` in `baka_auth.dart`).
|
||
- 👋 **Die Anmeldung ist jetzt wirklich nur noch für Gäste sichtbar.** Ohne
|
||
Server-Verbindung (kein eigener Melo-Account) erscheint weiterhin der
|
||
Hinweistext + Anmelde-Button wie bisher — Server-User sehen stattdessen
|
||
direkt das Adressfeld, ganz ohne Konto-Status-Zeile.
|
||
- 🎨 **Login-UI vergrößert.** "Beim Baka-Konto anmelden" ist jetzt ein
|
||
Button über die volle Breite (52 px hoch, größere Schrift); die Buttons
|
||
"Abbrechen"/"Anmelden" im Anmelde-Dialog haben jetzt eine Mindesthöhe von
|
||
48 px. Der Dialog hatte ohnehin nie ein Adressfeld — die Proxy-URL bleibt
|
||
fest im Code hinterlegt, nicht sichtbar oder änderbar.
|
||
- ✅ **Getestet:** 582 Tests grün (vorher 574), `flutter analyze` ohne
|
||
Befund. 8 neue Tests: `BakaAuth.autoAnmelden` (meldet an, greift nicht
|
||
ein wenn schon angemeldet, tut nichts ohne Zugangsdaten) sowie
|
||
Widget-Tests für den Server-User-Weg und den Rückfallweg bei
|
||
fehlgeschlagener Auto-Anmeldung in Download-Tab und YT-Suche-Tab.
|
||
|
||
### 🎚️📺 Equalizer-Fix (Xiaomi) + In-App-YouTube-Suche, Extra-Tab (2026-08-25)
|
||
|
||
- 🎚️ **Equalizer: "kein System-Klangeffekte" trotz Dolby Atmos behoben.**
|
||
`openSystemPanel()` nutzte bisher nur den Android-Standard-Intent
|
||
(`ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL`) — dafür registriert
|
||
MIUI/HyperOS auf dem POCO X7 Pro keine Activity, `resolveActivity()`
|
||
liefert dort immer `null`. Neu: zuerst der Xiaomi-Weg direkt zur
|
||
System-Ton-Seite (`com.android.settings.Settings$SoundSettingsActivity`,
|
||
wo Dolby Atmos liegt), danach `Settings.ACTION_SOUND_SETTINGS` als
|
||
universeller Fallback, zuletzt weiter der Android-Standard-Intent für
|
||
Geräte, die den unterstützen. Kotlin kompiliert sauber
|
||
(`gradlew :app:compileDebugKotlin`); echtes Testen auf einem POCO X7 Pro
|
||
war von hier aus nicht möglich.
|
||
- 📺 **In-App-YouTube-Suche — neuer Extra-Tab "YT-Suche" (zum Testen).**
|
||
Bisher ließ sich nur eine YouTube-Adresse einfügen; jetzt gibt es eine
|
||
echte Suche mit Ergebnisliste (Vorschaubild, Titel, Dauer) und
|
||
Download-Knopf pro Treffer. Nutzt den bereits vorhandenen
|
||
`/api/search`-Endpunkt des Baka-Proxys (yt-dlp-gestützt, dieselbe
|
||
Anmeldung wie der bestehende YouTube-Downloader) — kein neuer Server,
|
||
kein YouTube-API-Key nötig. Die Vorschaubilder kommen direkt von
|
||
YouTubes öffentlichem Thumbnail-CDN, aus der Video-ID der Ergebnis-URL.
|
||
Der Download-Knopf läuft über denselben Weg wie im Download-Tab
|
||
(Baka-Proxy → App-Zwischenordner → MediaStore → Bibliotheks-Scan).
|
||
- 🐛 **Beim Testen gefunden:** `YtDownloadService.herunterladen()`
|
||
(Future.any + `.timeout()`) lässt sich nicht sicher aus einem
|
||
`testWidgets()`-Test heraus aufrufen — der Timeout-Timer bleibt unter
|
||
Flutters `fake_async`-Testbindung dauerhaft "pending" und lässt den Lauf
|
||
hängen bzw. an der Pending-Timer-Prüfung scheitern (reproduziert auch
|
||
ganz ohne die neue UI). Genau deshalb hat auch der bestehende
|
||
Download-Knopf im Download-Tab keinen eigenen Widget-Test — die
|
||
Download-Logik selbst ist über `yt_download_test.dart` schon ausführlich
|
||
abgedeckt, an `YtDownloadService` wurde nichts geändert.
|
||
- ✅ **Getestet:** 574 Tests grün (vorher 557), `flutter analyze` ohne
|
||
Befund. Neu: Tests für `youtubeVideoId`/Thumbnail-Ableitung, für
|
||
`YtSearchService.suchen` (Anmeldung, Erfolg, 401, Fehlertext, Timeout,
|
||
neue Suche ersetzt alte Treffer) und zwei Widget-Tests für den neuen Tab
|
||
(Anmelde-Hinweis, Suchergebnisse mit Titel/Dauer).
|
||
|
||
### 🔒 Worktree-Lock gegen Doppelarbeit (2026-08-25)
|
||
|
||
Aus der Workflow-Analyse desselben Tages (Dustin↔Hermes↔Claude, siehe
|
||
Eintrag unten): zwei Sessions bekamen 11 Minuten auseinander denselben
|
||
Auftrag für diesen Worktree — die erste committete nicht rechtzeitig, die
|
||
zweite musste die fertige Arbeit nachträglich unversioniert einsammeln.
|
||
|
||
- `melo-app-workflow`-Skill (nicht Teil dieses Repos) hat jetzt eine
|
||
Pflicht-Regel: vor der ersten Änderung eine `.claude-worktree-lock`-Datei
|
||
im Worktree-Root auf Frische prüfen (< 60 Minuten = vermutlich aktiv →
|
||
erst Dustin fragen), sonst eigene Sperre setzen und am Ende entfernen.
|
||
- `.claude-worktree-lock` neu in `.gitignore` — lokaler Laufzeit-Zustand,
|
||
kein Projektstand.
|
||
- Test-Timeout-Vorgabe im Skill korrigiert: `flutter test` dauert bei 550+
|
||
Tests oft >400s: Hintergrund-Lauf statt Foreground-Timeout ist jetzt der
|
||
dokumentierte Standard.
|
||
- Kein Code geändert, nur `.gitignore` — kein Testlauf nötig.
|
||
|
||
### 🔐 Berechtigungen beim Start, schärferes Sperrbildschirm-Cover (2026-08-25)
|
||
|
||
Vier Punkte aus dem Auftrag geprüft — zwei davon waren schon erledigt:
|
||
|
||
- ✅ **Tab-Reihenfolge** (Meine Musik, Suchen, Download, Favoriten) und
|
||
✅ **konfigurierbare Schnellzugriffe in "Meine Musik"** (Checkboxen in
|
||
den Einstellungen) waren bereits vollständig umgesetzt — nichts zu tun,
|
||
siehe Test `home_shell_test.dart` bzw. `AppSettings.meineMusikSektionen`.
|
||
- 🔑 **Alle Berechtigungen beim ersten Start.** Bisher fragte die App das
|
||
Musik-Recht erst beim manuellen Scannen und das Benachrichtigungs-Recht
|
||
erst nach dem ersten abgespielten Titel — beides isoliert und spät.
|
||
`LibraryService.ensureStartupPermissions()` fragt jetzt gleich beim
|
||
App-Start beide Rechte nacheinander ab (nicht gleichzeitig —
|
||
`permission_handler` wirft sonst einen Fehler). Wird eines dauerhaft
|
||
verweigert, zeigt "Meine Musik" ein Hinweisbanner mit Button direkt zu
|
||
den App-Einstellungen (`openAppSettings`) — für die Benachrichtigung neu,
|
||
fürs Musik-Recht gab es das schon. Auch in den Einstellungen selbst gibt
|
||
es jetzt für beide Rechte eine eigene Zeile mit "Einstellungen öffnen".
|
||
- 🖼️ **Schärferes Cover für den Sperrbildschirm.** `audio_service` liefert
|
||
das Album-Cover fürs große Sperrbildschirm-Bild (MIUI & Co.) technisch
|
||
schon über die MediaSession — die extrahierte Auflösung beim
|
||
Android-Scan war mit 512px aber knapp. Jetzt 1024px.
|
||
- 🐛 **Dabei gefunden:** Der neue Start-Berechtigungs-Aufruf ließ einen
|
||
bestehenden Widget-Test (`home_shell_test.dart`) hängen — ein
|
||
unbedingter `notifyListeners()`-Aufruf ohne echte Wertänderung kollidierte
|
||
mit dessen Test-Teardown (nur ein `pump()`, kein `pumpAndSettle()`).
|
||
`LibraryService` meldet Änderungen an `permissionDenied` und
|
||
`notificationPermissionDenied` jetzt nur noch, wenn sich der Wert
|
||
tatsächlich ändert.
|
||
- ✅ **Getestet:** 557 Tests grün (vorher 550), `flutter analyze` ohne
|
||
Befund. Neu: Banner-Test für die verweigerte Benachrichtigung, Test für
|
||
die neue Berechtigungs-Zeile in den Einstellungen.
|
||
|
||
### 🧑🤝🧑 UX-Simulation, Teil 3: die zurückgestellten Punkte (2026-08-25)
|
||
|
||
Die vier Punkte aus Teil 2, die als "eigenes kleines Vorhaben" zurückgestellt
|
||
waren, sind jetzt auch erledigt:
|
||
|
||
- ⏹️ **Abbrechen-Knopf für YouTube-Downloads.** Ein hängender Download (bis
|
||
zu zwei mal 180s) ließ sich vorher nur durch Schließen der App stoppen.
|
||
`YtDownloadService` wartet jetzt mit `Future.any` gegen ein Abbruch-Signal
|
||
— die Netzwerk-Anfrage läuft im Hintergrund aus, die App wartet aber
|
||
nicht mehr darauf und meldet sich sofort zurück.
|
||
- 🔴 **Punkt am inaktiven Download-Unterreiter,** wenn dort im Hintergrund
|
||
ein Download läuft — man sah vorher nicht, dass beim Wechsel zu
|
||
YouTube/Server nebenan noch etwas passiert. `SubTabs` kann das jetzt für
|
||
jeden Reiter einzeln (neuer, optionaler `badges`-Parameter).
|
||
- 🔢 **Versionsnummer unter "Über Melo"** — dafür kam `package_info_plus`
|
||
als neue Abhängigkeit dazu (federated plugin, kein zusätzliches
|
||
Manifest nötig).
|
||
- 👆 **Mini-Player folgt jetzt dem Finger.** Vorher zählte nur ein kräftiger
|
||
Schwung (≥ 300 px/s); wer langsam, aber weit genug wischte, bekam gar
|
||
keine Reaktion — wie ein hängender Bildschirm statt "zu langsam
|
||
gewischt". Der Player führt die Bewegung jetzt sichtbar mit
|
||
(`AnimatedContainer.transform`) und entscheidet beim Loslassen über
|
||
Schwung **oder** zurückgelegte Strecke; ohne Wirkung schnappt er sichtbar
|
||
zurück. Nach unten bleibt weiterhin unbelegt (Absicht, unverändert).
|
||
- 🔧 **Nebenbei gefunden:** Drei bestehende Widget-Tests
|
||
(`hauptmenue_test.dart`, `home_shell_test.dart`,
|
||
`online_screen_test.dart`) bauten den Download-Tab ohne
|
||
`Provider<DownloadService>` auf — funktionierte bisher nur, weil niemand
|
||
ihn dort abfragte. Das Badge tut das jetzt app-weit; die drei
|
||
Test-Aufbauten sind entsprechend ergänzt.
|
||
- ✅ **Getestet:** 550 Tests grün (vorher 539), `flutter analyze` ohne
|
||
Befund. Neu: Abbruch-Test für den YouTube-Download (hängende Anfrage per
|
||
`Completer`), zwei Tests für das SubTabs-Badge, vier für die
|
||
streckenbasierten Wisch-Funktionen.
|
||
|
||
### 🧑🤝🧑 UX-Simulation, Teil 2: Player-Feinschliff, Downloads, Einstellungen (2026-08-25)
|
||
|
||
Zweiter Block derselben 39 Funde:
|
||
|
||
- 🎧 **Songtext-Icon ohne ID war ein toter Knopf** — sichtbar, tippbar, aber
|
||
ohne jede Wirkung. Jetzt ausgegraut mit erklärendem Tooltip, wenn kein
|
||
Songtext-Ziel bekannt ist.
|
||
- ⏱️ **Sleep-Timer-Restzeit war faktisch unsichtbar** (nur im Tooltip, den
|
||
kaum jemand per Long-Press entdeckt) — steht jetzt auch im Sheet.
|
||
- ↕️ **Warteschlange umsortieren war unauffindbar:** kein sichtbares Zeichen,
|
||
dass die Liste per Drag reagiert. Jetzt mit Drag-Handle-Symbol wie bei
|
||
Spotify/Apple Music.
|
||
- 👇 **Vollbild-Player ließ sich nicht wegwischen** — nur über den
|
||
Zurück-Pfeil schließbar, obwohl der Mini-Player schon Wischgesten kann.
|
||
Jetzt schließt Wischen nach unten den Player, wie bei Apple Music/Spotify.
|
||
- 🏷️ Fehlendes `tooltip:` am Schließen-Knopf des Songtext-Sheets ergänzt —
|
||
jeder andere Icon-Button der App hat einen.
|
||
- 📡 **YouTube-Downloads:** Zeitüberschreitung (Server erreichbar, braucht
|
||
nur zu lange) und toter Server meldeten sich bisher identisch — jetzt mit
|
||
eigener, ehrlicherer Meldung ("braucht zu lange" statt "nicht
|
||
erreichbar").
|
||
- 🔄 **Server-Tab blitzte beim Öffnen kurz "nicht verbunden" auf**, obwohl
|
||
verbunden — weil `build()` lief, bevor die gespeicherten Zugangsdaten
|
||
fertig geladen waren. Jetzt erst ein Ladezustand, dann die echte Antwort.
|
||
- 🗂️ **Einstellungen umsortiert:** Favoriten-Sync und Playlisten-Sync
|
||
standen unter "Speicher", obwohl sie nichts mit Speicherplatz zu tun
|
||
haben — jetzt bei "Musikserver", direkt beim Navidrome-Eintrag. Der
|
||
Navidrome-Eintrag selbst sagt jetzt, wofür er da ist ("Eigener
|
||
Musik-Server"), statt nur den Software-Namen zu zeigen.
|
||
- ✏️ Kommentar in `geteilte_adresse.dart` korrigiert: er behauptete, der
|
||
Server entscheide über nicht-YouTube-Adressen — tatsächlich lehnt
|
||
`YtDownloadService` sie schon vorher ab. Verhalten bewusst nicht
|
||
geändert (dafür gibt es einen eigenen Test), nur die Doku richtiggestellt.
|
||
- ⏸️ **Bewusst nicht angefasst:** das separate Server-Favoriten-Herz
|
||
(`ServerFavoriteButton`) bleibt wie dokumentiert lokal-only — das ist eine
|
||
bestehende, begründete Architektur-Entscheidung (siehe G3 im
|
||
UX-Review) und keine Kleinigkeit, die sich nebenbei mitreparieren lässt.
|
||
Ebenso zurückgestellt: Live-Mitführen des Fingers beim langsamen Wischen
|
||
am Mini-Player, ein Abbrechen-Knopf für laufende YouTube-Downloads, ein
|
||
Lauf-Badge auf dem inaktiven Download-Unterreiter und eine Versionsnummer
|
||
unter "Über Melo" (bräuchte eine neue Abhängigkeit) — alles eigene
|
||
kleine Vorhaben, keine Fünf-Minuten-Fixe.
|
||
- ✅ **Getestet:** 539 Tests grün (vorher 537, 2 neu für die
|
||
Timeout-Unterscheidung beim YouTube-Download), `flutter analyze` ohne
|
||
Befund.
|
||
|
||
### 🧑🤝🧑 UX-Simulation: Mehrfachauswahl, Baka-Login, Bestätigungen, Suche (2026-08-25)
|
||
|
||
7 Agenten sind die App wie ein normaler Nutzer durchgegangen (Erststart,
|
||
Bibliothek, Download, Suche, Favoriten, Player, Einstellungen) und haben 39
|
||
konkrete Reibungspunkte gefunden — verglichen mit Apple Music/Spotify. Erster
|
||
Block der Fixe:
|
||
|
||
- 🖐️ **Mehrfachauswahl funktionierte nur im Lieder- und Favoriten-Reiter.**
|
||
Öffnete man eine Kategorie oder das Album eines Künstlers, tat langes
|
||
Drücken auf einen Titel gar nichts — derselbe Ripple-Effekt, aber ohne
|
||
Wirkung. Die Auswahl-Leiste und die Sammel-Aktionen ("Zur Warteschlange",
|
||
"Zu Wiedergabeliste") aus `SortableSongList` sind jetzt in
|
||
`lib/shared/auswahl_leiste.dart` geteilt und laufen auch in der
|
||
Album-/Kategorie-Detailansicht (`TitelListenScreen`, jetzt mit Sortierung
|
||
und Shuffle wie der Lieder-Reiter) und in der Künstlerseite
|
||
(`KuenstlerScreen`).
|
||
- 🔁 **Zwei "Favoriten"-Listen mit unterschiedlichem Funktionsumfang.** Der
|
||
Favoriten-Tab bot Sortieren/Shuffle/Auswahl, der über Playlisten
|
||
erreichbare zweite Favoriten-Bildschirm zeigte dieselben Songs nur nackt.
|
||
Beide zeigen jetzt dieselbe `SortableSongList`.
|
||
- 🔐 **Baka-Login blieb bei falschem Passwort bis zu 15 Sekunden lang
|
||
stumm.** Der Dialog schloss sich sofort beim Antippen von "Anmelden",
|
||
noch bevor die Anfrage überhaupt losging; der Fehler kam erst danach in
|
||
einer unauffälligen grauen Zeile. Jetzt bleibt der Dialog offen, zeigt
|
||
einen Ladespinner und den Fehler direkt darin — wie beim (bereits guten)
|
||
Navidrome-Login.
|
||
- 🗑️ **Cache leeren und Navidrome-Abmelden liefen ohne Rückfrage.** Ein
|
||
versehentlicher Tipp auf das kleine Papierkorb- bzw. Logout-Icon hat
|
||
sofort gewirkt. Beide fragen jetzt nach, das einzelne Entfernen eines
|
||
Downloads ebenso (analog zum bereits vorhandenen "Alle entfernen"-Dialog).
|
||
- 📡 **Downloads bei toter Serververbindung meldeten "War schon
|
||
heruntergeladen"** — dieselbe Meldung wie bei tatsächlich schon
|
||
vorhandenen Titeln. Jetzt erscheint der wirkliche Grund
|
||
("Nicht mit dem Musikserver verbunden"). YouTube-Fehlermeldungen sind
|
||
außerdem jetzt rot statt in derselben Neutralfarbe wie Erfolgsmeldungen.
|
||
- 🔍 **Suche:** Die Tastatur blieb nach Auswahl eines Treffers offen und
|
||
verdeckte die Liste — schließt jetzt automatisch. "Nichts gefunden" nennt
|
||
jetzt den gesuchten Begriff. Einzelne Verlaufseinträge lassen sich
|
||
entfernen, ohne den ganzen Suchverlauf zu löschen.
|
||
- 🎤 **Zwei irreführende Icons:** "Musik-Berechtigung" in den Einstellungen
|
||
zeigte ein Mikrofon (fragt aber Speicherzugriff ab, kein Mikrofon);
|
||
"Musik erkennen" zeigte ein Fragezeichen-Symbol (Hilfe-Icon) statt eines
|
||
erkennbaren Mikrofon-Symbols.
|
||
- ✏️ Kleinere Textkorrekturen: der Hinweis "beim Baka-Konto anmelden" verwies
|
||
auf einen nicht existierenden Tab "Online" (richtig: Download-Tab); die
|
||
ReplayGain-Beschreibung nannte unerklärten Audio-Fachjargon.
|
||
- ✅ **Getestet:** 537 Tests grün (vorher 533, 4 neu für `verlaufOhne`),
|
||
`flutter analyze` ohne Befund.
|
||
|
||
### 🎨 Cover-Farbe, Teilen, Android Auto, geschärfte Typografie (2026-08-24)
|
||
|
||
Die P3-Liste aus dem Review.
|
||
|
||
- 🌈 **Der Player nimmt die Farbe des Covers auf.** Bisher war er für jeden
|
||
Titel gleich schwarz; jetzt läuft ein Verlauf aus der prägenden Farbe des
|
||
Albums nach unten in Schwarz aus. **Ohne neue Abhängigkeit:** die
|
||
Farbwahl ist eine reine Funktion über die Bildpunkte und dadurch prüfbar.
|
||
Nicht einfach die häufigste Farbe — Cover sind oft überwiegend dunkel oder
|
||
grau, und dann sähe wieder alles gleich aus. Häufigkeit **und** Farbigkeit
|
||
entscheiden zusammen. Anschließend wird so weit abgedunkelt, dass weiße
|
||
Schrift darauf lesbar bleibt.
|
||
|
||
- 📤 **„Teilen → Melo" aus der YouTube-App.** Vorher musste man die Adresse
|
||
von Hand kopieren und einfügen. Die App springt in den Download-Bereich und
|
||
trägt die Adresse ein — **ohne** den Download zu starten: Kategorie und
|
||
Speicherort will man vorher noch wählen können. Die geteilte Nachricht
|
||
enthält meist Titel und „über @YouTube" drumherum; daraus wird die Adresse
|
||
herausgelöst. Bewusst nicht auf YouTube eingeschränkt — der Downloader
|
||
läuft über yt-dlp und kann mehr, und was davon geht, entscheidet der Server.
|
||
|
||
- 🚗 **Android Auto blättert jetzt wirklich durch die Bibliothek.** Der
|
||
MediaBrowserService war im Manifest zwar angemeldet, lieferte aber nie
|
||
Inhalte — die Bibliothek blieb dort leer. Vier Ordner wie in der App:
|
||
Favoriten · Zuletzt hinzugefügt · Kategorien · Künstler. Ein Titel im Auto
|
||
startet den **ganzen Ordner** ab dieser Stelle, nicht nur das eine Lied.
|
||
Die Adressen halten Doppelpunkte und Schrägstriche aus — „Intro: Anfang"
|
||
und „AC/DC" sind normale Namen.
|
||
|
||
- 🔠 **Typografie geschärft, ohne neue Schrift.** Melo bleibt bei der
|
||
System-Schrift: sie ist immer da, trägt jede Sprache und kostet nichts an
|
||
App-Größe. Geschärft wurde vor allem die **Laufweite** — große Grade stehen
|
||
enger, damit die Zeile als ein Wortbild liest; Abschnitts-Beschriftungen in
|
||
Großbuchstaben dagegen weiter, weil die Luft brauchen.
|
||
|
||
- 🐛 **Dabei gefunden:** Die drei Bildschirm-Überschriften („Download",
|
||
„Favoriten", „Suchen") setzten ihre Größe **von Hand**, während das Theme
|
||
eine eigene Stufe dafür vorhielt — die nie benutzt wurde. Eine Änderung am
|
||
Theme wäre nirgends angekommen. Jetzt gehen alle drei durch eine gemeinsame
|
||
Überschrift.
|
||
|
||
- ↩️ **Und eine Rücknahme:** Ich hatte den Fließtext dichter gesetzt und damit
|
||
eine Regel gebrochen, die seit Längerem als Test festgehalten ist
|
||
(„Fließtext hat mindestens 1,35 Zeilenhöhe"). Die Regel ist älter als diese
|
||
Politur und hat einen Grund — zurückgenommen wurde deshalb mein Code, nicht
|
||
der Test.
|
||
|
||
- ✅ **Getestet:** 533 Tests grün (vorher 500), `flutter analyze` ohne Befund,
|
||
Release-APK gebaut; Auto-Eintrag und Teilen-Filter im fertigen APK
|
||
nachgeprüft. Neu: 9 Tests für die Cover-Farbe, 8 für das Herauslösen der
|
||
geteilten Adresse, 9 für die Adressen des Auto-Baums und 7 für die
|
||
Stufenleiter der Schrift.
|
||
|
||
|
||
### ✨ Politur: Wischen, wandernde Cover, Alphabet-Sprung, Mehrfachauswahl (2026-08-24)
|
||
|
||
Die P2-Liste aus dem Review — lauter Kleinigkeiten, die man einzeln nicht
|
||
vermisst und zusammen sofort merkt.
|
||
|
||
- 🎞️ **Das Coverbild wandert.** Beim Öffnen der Vollbild-Wiedergabe springt
|
||
kein neuer Bildschirm auf; das Bild aus der Leiste wächst an seinen Platz.
|
||
- 👆 **Wischen am Mini-Player.** Nach oben öffnet die Wiedergabe, seitwärts
|
||
wechselt den Titel. Mit Schwelle: der Mini-Player ist zugleich ein Knopf,
|
||
und beim Antippen wandert der Finger fast immer ein paar Pixel — ohne
|
||
Schwelle spränge bei jedem zweiten Tipp der Titel. Nach unten ist bewusst
|
||
unbelegt, damit niemand die Wiedergabe aus Versehen wegschiebt.
|
||
- 🎨 **Die Künstlerliste hat Bilder** und nennt die Zahl der Alben. Dahinter
|
||
jetzt eine Künstlerseite mit seinen Alben, darunter alle Titel — vorher
|
||
stand bei einem Künstler mit acht Alben alles ungeordnet untereinander.
|
||
Bei nur einem Album entfällt die Zwischenstufe.
|
||
- 🔤 **Alphabet-Sprung am rechten Rand.** Erscheint nur, wo er stimmt: bei
|
||
Sortierung nach Namen und ab 30 Titeln. Bei „Zuletzt hinzugefügt" stünden
|
||
die Buchstaben in willkürlicher Reihenfolge. Umlaute zählen zu ihrem
|
||
Grundbuchstaben, Ziffern und Zeichen sammeln sich unter „#" — dieselbe
|
||
Regel wie die Sortierung selbst.
|
||
- ☑️ **Mehrfachauswahl.** Langes Drücken wählt aus, danach wählt jeder Tipp
|
||
weitere Titel. Oben stehen „Zur Warteschlange" und „Zu Wiedergabeliste".
|
||
Wer zwanzig Lieder in eine Liste wollte, tippte vorher sechzig Mal.
|
||
- ♿ **Abgeschaltete Systemanimationen gelten jetzt überall.** Bisher hielt
|
||
sich nur die Balken-Animation daran; Reiterwechsel, Songtext und
|
||
Mini-Player zogen weiter durch.
|
||
- 📱 **Querformat und Tablet.** Der Player legt Cover und Bedienung
|
||
nebeneinander, statt vom Cover einen Streifen übrig zu lassen oder die
|
||
Knöpfe aus dem Bild zu schieben. Auf breiten Schirmen bekommt der Text eine
|
||
Obergrenze, statt über die ganze Breite zu zerren.
|
||
|
||
- 🐛 **Beim Bauen gefunden:** Der Alphabet-Sprung landete bei absteigender
|
||
Sortierung am **Ende** eines Buchstaben-Blocks statt an seinem Anfang. Der
|
||
Index wird jetzt direkt auf der angezeigten Reihenfolge gebaut, mit Test
|
||
für beide Richtungen.
|
||
|
||
- 🔍 **Und ein hängender Test aufgeklärt.** Der neue Auswahl-Test kam nie
|
||
zurück — dieselbe Signatur wie der seit dem 21.8. übersprungene Test im
|
||
BACKLOG. Ursache: **Aufbau in `setUp`.** Das läuft außerhalb der Testzone,
|
||
also liefen Datenbank und Dienste in echter Zeit, während der Test in
|
||
Testzeit auf sie wartete. Aufbau in den Testkörper verschoben → fünf Tests
|
||
in einer Sekunde. Der alte Fall im BACKLOG hat eine andere Ursache
|
||
(nachgeprüft: `db.close()` ist es dort nicht), aber die Spur ist dort
|
||
notiert.
|
||
|
||
- 🔍 **Aus dem Code-Review nachgebessert — sieben Punkte, einer davon schwer:**
|
||
**(1)** Die Alphabet-Leiste wurde **breiter, je weniger Buchstaben** sie
|
||
hatte. Jeder Buchstabe skalierte auf die volle Höhe seines Platzes. Bei
|
||
einem Album mit 40 Titeln „Track 01…40" gäbe es genau einen Buchstaben —
|
||
die Leiste wäre 528 dp breit geworden und die Songliste vollständig
|
||
verschwunden. Feste Breite jetzt, und ab drei verschiedenen Buchstaben
|
||
überhaupt erst sichtbar.
|
||
**(2)** Die neue Künstlerseite baute **alle** Titel sofort. Jede Zeile hört
|
||
auf den Player und öffnet für ihr Herz eine eigene Abfrage — bei einem
|
||
Künstler mit 300 Titeln wären das 300 Abos beim Öffnen. Vorher war die
|
||
Liste faul; das war ein Rückschritt von mir.
|
||
**(3)** Wer Systemanimationen abgeschaltet hat, hätte beim mitlaufenden
|
||
Songtext einen Absturz bekommen: die Bildlauf-Animation verträgt keine
|
||
Dauer null. Jetzt wird gesprungen — das ist ohnehin, was die Einstellung
|
||
meint.
|
||
**(4)** Die feste Zeilenhöhe war mit 64 zu klein (ein `ListTile` mit
|
||
Untertitel ist 72). Sobald der Schnellzugriff aktiv wurde, schrumpften alle
|
||
Zeilen sichtbar gegenüber jeder anderen Liste. Außerdem wird die
|
||
Schriftskalierung jetzt an einer echten Schriftgröße gemessen statt an 1.0
|
||
— Android skaliert seit Version 14 nichtlinear.
|
||
**(5)** Titel, die schon in der Zielliste waren, wurden **verschoben** statt
|
||
übersprungen, und die Meldung zählte sie trotzdem mit. Jetzt: „7 hinzugefügt
|
||
· 3 waren schon drin".
|
||
**(6)** Ein Fehler mitten im Stapel brach still ab. Jetzt wird gesagt, wie
|
||
weit es kam.
|
||
**(7)** Die Zurück-Geste verließ den Bildschirm, statt die Auswahl zu
|
||
beenden — zwanzig markierte Titel mit einer Geste weg, die überall sonst
|
||
„einen Schritt zurück" heißt.
|
||
|
||
- 🧹 **Selbst gefunden:** In der Künstlerliste hing der Datenbank-Strom an
|
||
`CategoryService` und wurde bei **jeder** Kategorie-Meldung neu aufgesetzt
|
||
— während eines Scans also laufend. Derselbe Fehler, den der Review mir
|
||
eine Runde zuvor bei der Suche gezeigt hatte.
|
||
|
||
- ✅ **Getestet:** 500 Tests grün (vorher 457), `flutter analyze` ohne Befund,
|
||
Release-APK gebaut. Neu: 8 Tests für die Wisch-Schwellen, 10 für den
|
||
Alphabet-Index, 5 für die Breite der Leiste (inklusive des Falls mit einem
|
||
einzigen Buchstaben), 11 für die Auswahl-Regeln und Meldungen, 5
|
||
Widget-Tests für den Auswahl-Modus, 3 für die Album-Gruppierung und 3 für
|
||
die Künstler-Zeile.
|
||
|
||
|
||
### 🧩 Die letzten vier Punkte aus dem Review (2026-08-23)
|
||
|
||
**G2 — Server-Bereich.** Ein Tipp auf ein Album spielte sofort das ganze
|
||
Album ab; hineinsehen ging nicht.
|
||
|
||
- 💿 **Album- und Künstler-Ansicht.** Großes Cover, Künstler, Titelzahl,
|
||
Gesamtdauer, „Abspielen" und „Zufällig" — darunter die Titelliste mit
|
||
Nummer und Dauer. Antippen startet **an dieser Stelle**, nicht am Anfang.
|
||
Der laufende Titel ist auch hier markiert, und schon geladene Titel tragen
|
||
ein Häkchen.
|
||
- 📄 **Mehr als 50 Alben.** Die Liste hörte bei 50 auf, ohne dass etwas
|
||
darauf hinwies. Jetzt gibt es „Mehr Alben laden", und wenn der Server
|
||
weniger als eine volle Seite liefert, verschwindet der Knopf von selbst.
|
||
- 🚫 **Nicht umgesetzt:** „Server-Bereich aus dem Download-Tab lösen" stand
|
||
auch im Befund — das widerspricht aber Commit `34d6d8e` („Auf Wunsch von
|
||
Dustin"), mit dem der Tab bewusst wieder „Download" heißt. Die
|
||
Tab-Struktur bleibt unangetastet. Ebenso weggelassen: eine Suche über den
|
||
Server, weil die Suche ausdrücklich rein lokal bleiben soll.
|
||
|
||
**G8 — Songtext läuft mit.** Bisher eine Textwand ohne Bezug zur Wiedergabe.
|
||
|
||
- 🎤 Trägt der Text Zeitmarken (LRC), läuft er jetzt **mit**: die aktuelle
|
||
Zeile ist hell und größer, der Rest gedämpft, und die Ansicht schiebt sie
|
||
in die Mitte. **Antippen springt an die Stelle im Lied.**
|
||
- 📃 Ein Text ohne Zeitmarken bleibt eine Textwand — beides kommt vor, je
|
||
nach Tag und Server, und die App schaut nach, statt zu raten.
|
||
|
||
**G10 — Cover bleiben jetzt da.** `Image.network` merkt sich Bilder nur im
|
||
Arbeitsspeicher; nach jedem Neustart fragte jede Zeile ihr Cover erneut beim
|
||
Server an, und ohne Netz gab es gar keins.
|
||
|
||
- 🖼️ Cover landen in einem eigenen Ordner und werden nur einmal geholt. Der
|
||
Schlüssel hängt an der Album-Kennung, **nicht** an der Adresse — die trägt
|
||
bei jedem App-Start ein neues Token, und der Ordner wäre sonst gewachsen,
|
||
ohne je einen Treffer zu liefern.
|
||
- 🧹 Bewusst im Cache-Ordner: ein Cover ist ersetzbar. Räumt Android auf,
|
||
lädt es sich beim nächsten Mal neu — anders als die Musik-Downloads.
|
||
- ⚠️ Nur echte Bilder werden abgelegt: Subsonic meldet Fehler mit HTTP 200
|
||
und JSON, und das läge sonst dauerhaft als „Cover" im Ordner.
|
||
|
||
**Aus dem Code-Review nachgebessert — sieben Punkte:**
|
||
|
||
- 🤍 **Das Herz behielt beim Titelwechsel seinen Zustand.** Einen Server-Titel
|
||
favorisieren, der Player geht zum nächsten — und der zeigte sich als
|
||
Favorit, obwohl er nie einer war. Der nächste Tipp hätte ihn dann
|
||
„entfavorisiert".
|
||
- 🖼️ **Beim Scrollen zeigten Zeilen kurz das Cover der vorherigen.** Listen
|
||
verwenden ihre Zeilen wieder; ohne Schlüssel behielt die Bildabfrage das
|
||
alte Ergebnis, bis das neue da war — bei ungecachten Covern sekundenlang.
|
||
Ein Rückschritt gegenüber dem vorherigen Stand, deshalb hier mitbehoben.
|
||
- 🎤 **Der neue mitlaufende Songtext funktionierte für Server-Titel gar
|
||
nicht.** Ihm wurde die Abspiel-Adresse statt der Server-Kennung
|
||
übergeben; die App fragte den Server nach einem Titel namens „https://…"
|
||
und bekam nie einen Text.
|
||
- 🎨 **Ein Cover, das einmal nicht lud, blieb die ganze Sitzung grau.** Startet
|
||
die App ohne Netz, waren alle Cover bis zum Neustart weg — auch wenn die
|
||
Verbindung längst wieder stand. Fehlschläge werden nicht mehr gemerkt.
|
||
- 🚨 **„Server nicht erreichbar" sah aus wie „Album hat keine Titel".** Beide
|
||
Abfragen verschluckten ihre Fehler und lieferten eine leere Liste; der
|
||
Wiederholen-Knopf, den ich gebaut hatte, war damit unerreichbar.
|
||
- 🎸 **Die Künstler-Ansicht wäre immer leer geblieben.** Die App las die Titel
|
||
aus `getArtist`, wo die Subsonic-Schnittstelle sie gar nicht mitliefert —
|
||
Alben kommen dort ohne ihre Titel. Jetzt wird je Album nachgefragt.
|
||
(Vorbestehend, aber ich habe einen ganzen Bildschirm darauf gebaut.)
|
||
- 🧩 Dazu ein seltener, aber dauerhafter Fall: zwei gleichzeitige Abrufe
|
||
desselben Covers schrieben in dieselbe Zwischendatei und konnten ein
|
||
zerschnittenes Bild hinterlassen, das nie wieder verschwindet.
|
||
|
||
- 🧹 **Selbst gefunden:** Das Häkchen „schon geladen" fragte pro Zeile die
|
||
Platte ab — und die Zeile zeichnet sich bei jedem Positionswechsel neu.
|
||
Das wäre eine Dateiprüfung pro Sekunde und Titel gewesen. Jetzt einmal je
|
||
Bildschirm aus der Datenbank.
|
||
|
||
- ✅ **Getestet:** 457 Tests grün (vorher 433), `flutter analyze` ohne Befund,
|
||
Release-APK gebaut. Neu: 16 Tests für den LRC-Parser, 5 für den
|
||
Cover-Schlüssel und 3 für die Album-Daten.
|
||
|
||
**G3 — Server-Titel nicht länger zweiter Klasse.**
|
||
|
||
- 🤍 Das Herz ist bei Server-Titeln nicht mehr ausgegraut, sondern
|
||
favorisiert **am Server** (`star`/`unstar`) — genau dort, wo der
|
||
Favoriten-Abgleich in den Einstellungen sie auch wieder abholt. Ein Titel
|
||
der Bibliothek wird weiterhin lokal favorisiert.
|
||
- ℹ️ Weiterhin offen: Wiedergabezähler, Historie und Kategorien gibt es für
|
||
reine Server-Titel nicht — dafür bräuchten sie eine Zeile in der
|
||
Bibliothek, und das wäre ein eigener Umbau.
|
||
|
||
|
||
### 📥 Alben und Künstler offline mitnehmen — und der Zwischenspeicher hat endlich eine Grenze (2026-08-23)
|
||
|
||
Bisher landete Musik nur zufällig auf dem Gerät: was man abspielte, blieb
|
||
nebenbei liegen. Gezielt „dieses Album für die Zugfahrt" gab es nicht. Und
|
||
dieser Zwischenspeicher wuchs **unbegrenzt** — es gab nur „alles löschen".
|
||
|
||
- 📥 **Download-Pfeil neben jedem Album und Künstler** im Bereich
|
||
Download → Server. Während es läuft, steht oben ein Fortschritt mit
|
||
Abbruch-Knopf.
|
||
- ⚠️ **Rückfrage bei großen Mengen.** Ein Album geht ohne Nachfrage durch;
|
||
ab 30 Titeln fragt die App erst („347 Titel, geschätzt etwa 2100 MB").
|
||
Ein ganzer Künstler soll niemandem aus Versehen das Datenvolumen kosten.
|
||
- 🗂️ **Zwei getrennte Töpfe.** Bewusste Downloads liegen **nicht** im
|
||
Cache-Ordner. Der Grund ist keine Geschmacksfrage: den Cache-Ordner darf
|
||
Android bei Speichernot jederzeit selbst leeren — genau das darf einem
|
||
Album, das man mitgenommen hat, nicht passieren. Downloads liegen deshalb
|
||
neben der Datenbank, wo das System nichts anrührt.
|
||
- 🚧 **Obergrenze für den Zwischenspeicher**, voreingestellt 2 GB, in den
|
||
Einstellungen wählbar (aus / 512 MB / 1 / 2 / 4 / 8 GB). Ist sie erreicht,
|
||
fliegt das am längsten nicht Gehörte zuerst raus. **Heruntergeladene Titel
|
||
sind davon nie betroffen** — wer ein Album mitnimmt, hat das entschieden,
|
||
und die App nimmt es ihm nicht wieder weg.
|
||
- 📋 **Liste „Heruntergeladen"** in den Einstellungen: Titel, Künstler,
|
||
Größe, einzeln oder alle entfernbar. Sie kommt aus der Datenbank und nicht
|
||
aus dem Ordner — die Dateien heißen nach einem Hash und stünden dort sonst
|
||
als „a3f9…mp3".
|
||
- ▶️ **Die Wiedergabe schaut erst in die Downloads, dann in den
|
||
Zwischenspeicher.** Ein mitgenommener Titel hängt nie am Netz, auch wenn
|
||
zufällig eine Cache-Kopie existiert, die morgen verdrängt sein kann.
|
||
- 🧹 **Nebenbei aufgeräumt** (die Dateien waren ohnehin offen): die
|
||
Emoji-Knöpfe „📀 Alben" und „🎤 Künstler" heißen jetzt schlicht „Alben"
|
||
und „Künstler", das grelle `Colors.redAccent` ist überall dem Melo-Rot
|
||
gewichen, und die Einstellungen heißen nicht mehr „Settings".
|
||
- 🔍 **Aus dem Code-Review nachgebessert — zehn Punkte, vier davon ernst:**
|
||
**(1)** „Aus" bewirkte das Gegenteil. Bei 0 MB übersprang die App das
|
||
Aufräumen ganz, legte aber weiter jeden Titel ab — genau der unbegrenzt
|
||
wachsende Speicher, den diese Änderung beheben soll. „Aus" heißt jetzt
|
||
wirklich: nichts behalten.
|
||
**(2)** Wer sich erst **in** der Sitzung am Musikserver anmeldete, konnte
|
||
nichts herunterladen. Der Dienst hielt eine eigene Verbindung, die nur
|
||
beim App-Start eingerichtet wurde; die Titelliste kam, der Download lief
|
||
ins Leere. Erst ein Neustart half.
|
||
**(3)** Die Aufräum-Aktion konnte Dateien löschen, die die **laufende**
|
||
Warteschlange schon als Quelle eingetragen hatte — die Wiedergabe wäre
|
||
mitten im Album abgebrochen, ohne auf Streamen zurückzufallen. Benutzte
|
||
Dateien sind jetzt geschützt; im Zweifel bleibt die App lieber kurz über
|
||
der Grenze, als die Musik abzuwürgen.
|
||
**(4)** Ein bewusst heruntergeladener Titel wurde beim Abspielen **noch
|
||
einmal** in den Zwischenspeicher geladen — doppelter Platz, doppeltes
|
||
Datenvolumen.
|
||
Dazu sechs kleinere: ein einzelner Fehlschlag verdeckte nicht mehr den
|
||
Erfolg der übrigen Titel („18 heruntergeladen · 2 fehlgeschlagen"); eine
|
||
Datei ohne Buchführungs-Zeile (App mittendrin beendet) wird jetzt
|
||
nachgetragen statt für immer unsichtbar zu bleiben; zweimal antippen meldet
|
||
nicht mehr fälschlich Erfolg; „Lädt 21 von 20" gibt es nicht mehr; eine
|
||
gesenkte Grenze wirkt sofort statt erst beim nächsten gestreamten Titel;
|
||
und drei ungenutzte Methoden sind raus.
|
||
|
||
- 🕐 **Auch aus dem Review:** Der „zuletzt gehört"-Stempel wurde beim
|
||
**Aufbau** der Warteschlange gesetzt — damit hatten nach einem Albumstart
|
||
fünfzig Dateien fast denselben Zeitstempel und die Verdrängung wusste nicht
|
||
mehr, was wirklich gehört wurde. Gestempelt wird jetzt, wenn ein Titel
|
||
tatsächlich losspielt.
|
||
|
||
- ✅ **Getestet:** 433 Tests grün (vorher 411), `flutter analyze` ohne
|
||
Befund, Release-APK gebaut. Neu: 13 Tests für die Verdrängungs-Regel
|
||
(welche Datei weicht wann, bei gleichem Zeitstempel nie zufällig, und
|
||
benutzte Dateien nie) und 9 für Rückfrage-Schwelle, Größenschätzung und
|
||
Dateinamen.
|
||
|
||
|
||
### ▶️ Man sieht jetzt, welcher Titel gerade läuft (2026-08-23)
|
||
|
||
Bisher scrollte man durch die Bibliothek und musste raten, wo man gerade
|
||
ist — die einzige Rückmeldung war die Leiste ganz unten.
|
||
|
||
- 🎚️ **Drei tanzende Balken über dem Coverbild** des laufenden Titels, sein
|
||
Name in Rot. Die Balken liegen **auf** dem Cover statt daneben: eine vierte
|
||
Spalte hätte dem Titel Platz genommen, und die Zeile wäre bei jedem
|
||
Titelwechsel in der Breite gesprungen.
|
||
- ⏸️ **Pausiert bleibt die Markierung stehen, die Balken stehen still.** Man
|
||
sieht weiter, wo man ist, und zugleich, dass gerade nichts vorangeht.
|
||
- 🌐 **Überall zugleich.** Die Markierung sitzt in der Songzeile selbst, also
|
||
gilt sie in „Meine Musik“, Favoriten, Suche, hinter einem Künstler, hinter
|
||
einer Kategorie, in einer Wiedergabeliste und bei „Zuletzt hinzugefügt“ —
|
||
ohne dass irgendeine dieser Ansichten angefasst werden musste. Die
|
||
Warteschlange bekommt dasselbe Zeichen, damit man dieselbe Stelle
|
||
wiedererkennt.
|
||
- ♿ **Wer Systemanimationen abgeschaltet hat, bekommt stehende Balken.** Eine
|
||
Endlosschleife ist genau das, was diese Einstellung vermeiden soll.
|
||
- 🐛 **Beim Testen gefunden:** Die Balken lasen die Animations-Einstellung im
|
||
falschen Moment (`initState`), was Flutter mit einem Fehler quittiert. Der
|
||
Test, der prüft, dass nichts endlos läuft, hat es aufgedeckt.
|
||
|
||
- ⚡ **Und beim Nachsehen noch etwas:** Zuerst hing *jede* sichtbare Zeile am
|
||
Wiedergabe-Zustand — der meldet aber auch den Pufferstand und feuert
|
||
mehrmals pro Sekunde. Die halbe Liste hätte sich also ständig neu
|
||
aufgebaut. Jetzt hört nur die eine laufende Zeile darauf; alle anderen
|
||
bekommen nur mit, wenn der Titel wechselt.
|
||
- 🔍 **Aus dem Code-Review nachgebessert:**
|
||
**(1)** Die Markierung erschien einen Frame zu spät. Scrollte man die
|
||
laufende Zeile aus dem Blick und zurück, ploppten Balken und rote Schrift
|
||
sichtbar nach — der Strom liefert seinen Wert erst im nächsten Frame. Jetzt
|
||
mit Startwert.
|
||
**(2)** Beim Wechsel auf „markiert" änderte die Zeile die Form ihres
|
||
Aufbaus, und Flutter warf sie deshalb weg und baute sie neu. Folge: das
|
||
Herz daneben verlor sein Abo und sah einen Moment lang leer aus — genau
|
||
bei dem Titel, den man gerade gestartet hat. Der Aufbau bleibt jetzt
|
||
gleich, nur der Strom wird an- und abgehängt.
|
||
**(3)** In der **Wiedergabeliste** fehlte die Markierung ganz. Der
|
||
Changelog-Eintrag oben behauptete zuerst das Gegenteil — diese Ansicht
|
||
baut ihre Zeilen selbst (rechts steht „Aus Playlist entfernen" statt Herz
|
||
und Menü) und lief deshalb nicht über die gemeinsame Songzeile. Sie hat
|
||
die Markierung jetzt wirklich.
|
||
Dazu eine Kleinigkeit: der Abdunkel-Schleier hatte seinen Eckenradius fest
|
||
verdrahtet und hätte bei einem anderen Cover-Radius nicht mehr gepasst.
|
||
|
||
- 🧪 **Testlücke geschlossen, die der Review benannt hat.** Geprüft waren nur
|
||
die Regel und die Balken für sich — die Verdrahtung dazwischen nicht. Genau
|
||
dort saßen alle drei Fehler oben. Es gibt jetzt fünf Tests dafür, unter
|
||
anderem einen, der nachweist, dass die Zeile beim Wechsel **dasselbe**
|
||
Element bleibt.
|
||
|
||
- ✅ **Getestet:** 411 Tests grün (vorher 396), `flutter analyze` ohne Befund,
|
||
Release-APK gebaut. Neu: 5 Tests für die Regel, wann eine Zeile markiert
|
||
wird (inklusive: ein Server-Titel markiert nie eine Bibliothekszeile),
|
||
5 Widget-Tests für die Balken und 5 für die Verdrahtung.
|
||
|
||
|
||
### 🔎 Die Suche trennt jetzt nach Titel, Künstler, Kategorien und Listen (2026-08-23)
|
||
|
||
Der Suchen-Tab war bisher **59 Zeilen**: ein Textfeld über einer flachen
|
||
Liederliste. Wer „Nightcore“ eingab, bekam alle Titel dieses Künstlers
|
||
untereinander — den Künstler selbst, seine Kategorie oder eine gleichnamige
|
||
Wiedergabeliste fand er nicht.
|
||
|
||
- 🗂️ **Vier Abschnitte statt einer Liste.** Titel · Künstler · Kategorien ·
|
||
Wiedergabelisten, jeder mit Überschrift und Trefferzahl. Alben stecken in
|
||
„Kategorien“ — der Album-Name *ist* in Melo die erste Kategorie eines
|
||
Titels, ein eigener Alben-Abschnitt wäre dieselbe Liste zweimal.
|
||
- ⬆️ **Treffer am Wortanfang stehen oben.** Wer „roses“ tippt, meint eher
|
||
„Roses“ als „Wild Roses“. Innerhalb dieser beiden Ränge alphabetisch.
|
||
- ⏱️ **Entprellt (250 ms).** Vorher baute jeder einzelne Tastendruck die
|
||
komplette Trefferliste neu auf.
|
||
- 🕘 **Letzte acht Suchen.** Sie stehen da, solange das Feld leer ist; Antippen
|
||
übernimmt den Begriff. Gemerkt wird ein Begriff erst beim Abschicken —
|
||
halbe Wörter aus dem Tippen sind keine Suche, die man wiederholen möchte.
|
||
- 🧹 **Der Tab sieht aus wie die anderen.** Er war ein `Scaffold` mit eigener
|
||
`AppBar` *innerhalb* eines Tabs, während „Meine Musik“ und „Favoriten“ eine
|
||
Kopfzeile im Inhalt haben. Jetzt einheitlich, mit demselben runden Suchfeld
|
||
wie auf der Startseite.
|
||
- ♻️ **Aufgeräumt, weil es sonst eine dritte Kopie gegeben hätte:** Die
|
||
Ansicht „Überschrift + Liederliste“ stand zweimal wortgleich im Baum
|
||
(hinter einem Künstler und hinter einer Kategorie). Sie ist jetzt eine
|
||
Klasse, die auch die Suche benutzt. Ebenso ist die einzelne Songzeile aus
|
||
der Liederliste herausgelöst — die Suche setzt einzelne Zeilen in ihre
|
||
Abschnitte, eine ganze Liste wäre dort eine verschachtelte Scrollfläche.
|
||
- 🐛 **Beim Bauen selbst gefunden und behoben:** Der Verlauf wurde zuerst
|
||
beim Aufbau der Trefferliste geschrieben. Das hätte eine Endlosschleife
|
||
ergeben — schreiben löst ein Neuzeichnen aus, das wieder schreibt.
|
||
- 📴 **Kein Server-Teil.** Bewusst so entschieden: die Suche läuft rein
|
||
lokal, damit sie sofort antwortet und ohne Netz funktioniert.
|
||
- 🔍 **Aus dem Code-Review nachgebessert (die wichtigsten drei):**
|
||
**(1)** Die Suche fasste „Neoni", „NEONI" und „Neoni " zu einem Treffer
|
||
zusammen — die Titel dazu wurden aber unter der rohen Schreibweise gesucht.
|
||
Ergebnis: „0 Titel" und ein leerer Bildschirm beim Antippen. Beide Seiten
|
||
benutzen jetzt dieselbe Normalform, und verschiedene Schreibweisen
|
||
desselben Künstlers fallen dabei zusammen statt sich gegenseitig zu
|
||
verstecken. Dasselbe galt für Kategorien.
|
||
**(2)** Eine Kategorie, an der nur noch gelöschte Titel hängen, erschien
|
||
als Treffer und führte ins Leere. Solche Treffer fallen jetzt weg.
|
||
**(3)** Alle Abschnitte sind auf fünf Einträge gedeckelt, nicht nur die
|
||
Titel. Eine Eingabe wie „a" hätte sonst hunderte Künstlerzeilen bei jedem
|
||
Neuzeichnen gebaut. Die Gesamtzahl steht ohnehin in der Überschrift.
|
||
Dazu kleinere Sachen: die beiden Datenbank-Ströme werden nicht mehr bei
|
||
jedem Neuzeichnen neu abonniert, der Fehlerfall der Wiedergabelisten wird
|
||
behandelt, und das Löschkreuz im Suchfeld erscheint sofort statt nach
|
||
250 ms — vorher sprang das Textfeld dabei um eine Knopfbreite enger.
|
||
|
||
- 🗑️ **Verlauf lässt sich löschen.** Ein „Löschen" neben der Überschrift.
|
||
(Ohne das hätte es keine Möglichkeit gegeben, gespeicherte Suchbegriffe
|
||
wieder loszuwerden.)
|
||
|
||
- ♻️ **Tot geworden und entfernt:** `MeloDb.searchSongs` samt Test — die
|
||
alte LIKE-Abfrage hat nach dem Umbau keinen Aufrufer mehr.
|
||
|
||
- ✅ **Getestet:** 396 Tests grün (vorher 360), `flutter analyze` ohne Befund,
|
||
Release-APK gebaut. Neu: 25 Tests für die Suchregeln und die Bündelung
|
||
nach Schreibweise, 7 für den Verlauf, 7 Widget-Tests für die Abschnitte
|
||
(inklusive einem, der prüft, dass wirklich entprellt wird).
|
||
|
||
|
||
### 🔁 Positions-Timer überlebt jetzt das Wegwischen (2026-08-23)
|
||
|
||
- ⏱️ **Behoben: nach dem Wegwischen der Benachrichtigung merkte sich die App
|
||
keine Hörposition mehr.** `stop()` brach dabei den Timer ab, der alle fünf
|
||
Sekunden die Wiedergabeposition sichert — und der entsteht nur **einmal**
|
||
beim App-Start. Einmal abgebrochen, kam er nie zurück: „Fortsetzen an alter
|
||
Stelle" hörte still auf zu funktionieren, und zum Server wurde nicht mehr
|
||
gemeldet, was gehört wurde. Erst ein Neustart half. Der Timer läuft jetzt
|
||
durch; er kostet nichts, weil er von selbst aussteigt, solange nichts
|
||
spielt. Abgebrochen wird er nur noch beim endgültigen Aufräumen.
|
||
|
||
- 📄 **Korrektur am eigenen Review-Bericht (K4).** Dort stand, die
|
||
Alben-Ansicht sei „verlorengegangen". Das war falsch: der Alben-Reiter wurde
|
||
**bewusst** durch „Kategorie" ersetzt — der Album-Name eines Liedes *ist* in
|
||
Melo seine erste Kategorie (`category_list.dart:12`, `kategorienAusTags`).
|
||
Was wirklich fehlt, ist die Album-**Detailansicht** (großes Cover,
|
||
Künstler, Gesamtdauer) und die Sortierung nach Tracknummer — letztere
|
||
braucht zuerst eine Schema-Erweiterung, weil die Tracknummer bisher
|
||
überhaupt nicht eingelesen wird. Im Bericht ist der Punkt richtiggestellt.
|
||
|
||
- ✅ **Getestet:** 360 Tests grün, `flutter analyze` ohne Befund.
|
||
|
||
### 🚑 Fünf P0-Fehler behoben: Benachrichtigung, Offline, Cover, Warteschlange (2026-08-23)
|
||
|
||
Ergebnis einer vollständigen Durchsicht der App gegen den Maßstab „Apple
|
||
Music". Fünf Punkte waren keine fehlenden Funktionen, sondern **Versprechen,
|
||
die die App gab und der Code nicht hielt**.
|
||
|
||
- 🔔 **Die Wiedergabe-Benachrichtigung erschien auf Android 13+ gar nicht.**
|
||
Dafür braucht das System die Berechtigung `POST_NOTIFICATIONS` — sie fehlte
|
||
im Manifest, auch im fertig gebauten APK. Die Musik lief, aber Notification
|
||
und die Bedienknöpfe darin blieben unsichtbar; steuern ließ sich nur in der
|
||
geöffneten App. Die Berechtigung ist jetzt drin und wird **erst dann**
|
||
erfragt, wenn wirklich ein Titel läuft — beim kalten Start käme die Frage
|
||
ohne Zusammenhang, und zweimal weggetippt sperrt Android sie dauerhaft.
|
||
|
||
- 📴 **Der Offline-Schalter tat nichts.** Er speicherte brav ein Ja/Nein, aber
|
||
**niemand las es**: die App streamte weiter und verbrauchte Mobilfunkdaten,
|
||
obwohl „Offline-Modus" anstand. Jetzt greift er an allen drei Wegen in die
|
||
Warteschlange — Abspielen, „Als Nächstes", „Zur Warteschlange". Titel vom
|
||
Gerät laufen immer, Titel vom Server nur, wenn sie schon hier liegen. Was
|
||
übersprungen wird, sagt die App: *„Offline-Modus: 3 Titel übersprungen —
|
||
nicht heruntergeladen"*, statt still eine kürzere Liste zu spielen.
|
||
|
||
- 🖼️ **Titel vom Server hatten nie ein Coverbild.** Die App konnte Cover nur
|
||
aus Dateien laden; das Bild vom Navidrome-Server liegt aber hinter einer
|
||
Web-Adresse. Jeder Server-Titel war deshalb ein graues Notensymbol — in der
|
||
Liste, im Player, auf dem Sperrbildschirm. Jetzt lädt die App auch
|
||
Web-Cover, und der Server-Browser gibt die Adresse überhaupt erst mit
|
||
(vorher wurde sie an beiden Stellen schlicht vergessen).
|
||
|
||
- ⏭️ **Warteschlange umsortieren riss die Wiedergabe auf.** Jedes Entfernen
|
||
und jedes Verschieben baute die *ganze* Warteschlange neu auf: hörbarer
|
||
Aussetzer, Sprung an den Titelanfang — und der laufende Titel wurde dabei
|
||
**jedes Mal erneut als Wiedergabe gezählt**. Die Sortierung „Wie oft
|
||
abgespielt" zählte damit Queue-Bedienung statt Hören. Jetzt wird nur der
|
||
eine betroffene Eintrag bewegt; die Wiedergabe merkt davon nichts.
|
||
|
||
- 🤍 **Das Herz bei Server-Titeln log.** Ein Titel, der nur am Server liegt,
|
||
hat keinen Eintrag in der Bibliothek — das Herz bekam deshalb eine leere
|
||
Kennung, füllte sich beim Antippen und legte einen Favoriten an, der in der
|
||
Favoritenliste nie auftauchte. Es ist jetzt sichtbar ausgegraut, mit dem
|
||
Hinweis „Nur für Titel in deiner Bibliothek".
|
||
|
||
- ⚡ **Nebenwirkung der Offline-Umstellung, aber eine gute:** „Als Nächstes"
|
||
und „Zur Warteschlange" sahen bisher gar nicht im Zwischenspeicher nach und
|
||
streamten einen Server-Titel auch dann, wenn er längst auf dem Gerät lag.
|
||
Alle drei Wege in die Warteschlange bauen die Abspielquelle jetzt an
|
||
derselben Stelle — ein bereits geladener Titel läuft immer von der Platte.
|
||
|
||
- 🧹 **Nebenbei:** „📴 Offline-Modus" heißt jetzt ohne Emoji „Offline-Modus"
|
||
(Emoji sehen auf jedem Hersteller-Handy anders aus und lassen sich nicht
|
||
einfärben), und der Untertitel sagt, was der Schalter wirklich tut.
|
||
|
||
- 🔍 **Aus dem Code-Review nachgebessert (drei Punkte):**
|
||
**(1)** Die Offline-Meldung hing an der falschen Stelle. Sie stand in der
|
||
Bibliotheksliste — die zeigt aber nur Titel vom Gerät, dort wird nie etwas
|
||
übersprungen. Beim Server-Album, wo es wirklich passiert, wurde sie
|
||
verworfen. Jetzt sitzt sie dort, wo sie greifen kann; und „nichts davon ist
|
||
heruntergeladen" erscheint nicht mehr als *„Fehler: …"* — das ist kein
|
||
Fehler, sondern die eingestellte Wahl.
|
||
**(2)** Beim Umsortieren wurde die Warteschlange erst *nach* dem Player
|
||
nachgeführt. In der Lücke dazwischen konnte der Player schon einen neuen
|
||
Titelindex melden, während die App noch die alte Liste kannte — falscher
|
||
Titel im Player, Wiedergabe für das falsche Lied gezählt. Buchführung steht
|
||
jetzt vor dem Player, genau wie beim normalen Abspielen.
|
||
**(3)** Die Abfrage der Benachrichtigungs-Berechtigung hatte keinen
|
||
Fehlerpfad. Läuft beim Start noch die Abfrage der Musik-Berechtigung, wirft
|
||
Android — das wäre als unbehandelter Fehler durchgeschlagen. Jetzt wird es
|
||
nur protokolliert; die Wiedergabe läuft weiter, nur eben ohne
|
||
Benachrichtigung.
|
||
|
||
- ✅ **Getestet:** 360 Tests grün (vorher 328), `flutter analyze` ohne Befund,
|
||
Release-APK gebaut. Im fertigen APK ist `POST_NOTIFICATIONS` nachgeprüft
|
||
enthalten. Neu: 39 Tests für Offline-Filter, Warteschlangen-Mutation,
|
||
Zähler-Nachführung, Server-Cover und das ausgegraute Herz. Entfallen: 9
|
||
Tests für `newPlayingIndex` — die Funktion gab es nur, um nach dem
|
||
Neuaufbau der Warteschlange den laufenden Titel wiederzufinden, und den
|
||
Neuaufbau gibt es nicht mehr.
|
||
|
||
- 📋 **Nicht in dieser Runde:** Alben-Ansicht, Suche über den Server,
|
||
gezieltes Herunterladen und die Cache-Obergrenze. Die stehen als P1 im
|
||
Review-Bericht unter `.ui-design/reviews/melo_vollwertigkeit_20260823.md`.
|
||
Dazu zwei Punkte, die erst bei dieser Arbeit auffielen und dort als **G9**
|
||
und **G10** stehen: `stop()` bricht den Positions-Timer dauerhaft ab (nach
|
||
dem Wegwischen der Benachrichtigung merkt sich die App keine Hörposition
|
||
mehr — vorbestehend), und die Server-Cover haben nur einen Zwischenspeicher
|
||
im Arbeitsspeicher, keinen auf der Platte.
|
||
|
||
### 🏷️ Der zweite Tab heißt wieder „Download" (2026-08-21)
|
||
|
||
- 📥 **Aus „Online" wird „Download".** Der Bereich behält seinen Inhalt
|
||
unverändert — YouTube-Downloader und Server-Bibliothek als Unterreiter.
|
||
Nur die Beschriftung im Hauptmenü ändert sich.
|
||
Die vier Bereiche heißen jetzt: **Meine Musik · Download · Suchen ·
|
||
Favoriten**.
|
||
- ⬇️ **Passendes Symbol dazu.** Statt der Note steht wieder ein Download-Pfeil
|
||
im Menü — genau das Symbol, das der Tab schon einmal hatte, bevor er in
|
||
„Online" umbenannt wurde. Also nichts Neues erfunden, sondern der frühere
|
||
Stand wiederhergestellt.
|
||
- 📄 **Auch die Überschrift im Bereich selbst zieht nach.** Sie stand noch auf
|
||
„Online" — ein Tab namens „Download", der auf einen Bildschirm namens
|
||
„Online" führt, wäre verwirrend gewesen.
|
||
- ✅ **Getestet:** 328 Tests grün, `flutter analyze` ohne Befund.
|
||
|
||
### 🧭 Hauptmenü wieder deutlich sichtbar (2026-08-21)
|
||
|
||
**Zuerst die Entwarnung:** Es fehlt nichts und nichts ist verschoben. Alle
|
||
vier Bereiche standen und stehen unten im Hauptmenü — `lib/main.dart` wurde
|
||
von der UI-Politur überhaupt nicht angefasst.
|
||
|
||
- 🐛 **Behoben: die Politur hatte das Menü abgeschwächt.** Zwei Fehler von
|
||
mir aus der letzten Runde:
|
||
- Ich hatte für **aktiv und inaktiv dieselbe Schriftgröße** (12) gesetzt.
|
||
Damit verlor der aktive Bereich den Größenunterschied (sonst 14 zu 12),
|
||
an dem man auf einen Blick erkennt, wo man ist.
|
||
- Die inaktiven Einträge liefen auf der **blassen Beiwerk-Stufe**. Ein
|
||
Hauptmenü ist kein Beiwerk — sie sind jetzt wieder kräftig.
|
||
- ✨ **Zusätzlich deutlicher gemacht:**
|
||
- Eine **Haarlinie über dem Menü** — auf schwarzem Grund ging die Leiste
|
||
sonst optisch im Inhalt auf.
|
||
- Der aktive Bereich hat jetzt ein **gefülltes Symbol** (ausgefülltes Herz,
|
||
volle Note). Wer Rot schlecht sieht, erkennt trotzdem, wo er steht —
|
||
vorher unterschied nur die Farbe.
|
||
- Der aktive Eintrag ist fetter gesetzt.
|
||
- 🔒 **Damit das keine Politur mehr abschwächen kann:** ein neuer Test prüft,
|
||
dass alle vier Bereiche vorhanden **und auf dem Bildschirm** sind, dass das
|
||
Menü am unteren Rand klebt, dass jeder Tipp dorthin wechselt, und dass der
|
||
aktive Bereich sich nicht nur durch Farbe abhebt.
|
||
- 🔧 **Details für Technikinteressierte:**
|
||
- Neu: `test/hauptmenue_test.dart` (10 Prüfungen).
|
||
- `bottomNavigationBarTheme`: keine feste `fontSize` mehr (damit Flutters
|
||
14/12 gelten), `unselectedItemColor` von `text3` auf `text2`,
|
||
`showUnselectedLabels` ausdrücklich gesetzt.
|
||
- Beim Schreiben des Tests ist eine **Test-Falle** aufgefallen und gelöst:
|
||
`await db.close()` nach einem `tester.tap` lässt den Testlauf
|
||
**unbegrenzt hängen**. Rezept dagegen steht im Test und in `BACKLOG.md`.
|
||
Beim schon bekannten Hänger in `song_detail_sheet_test.dart` hilft es
|
||
allerdings nicht — dort ist die Ursache eine andere, jetzt ebenfalls im
|
||
Backlog vermerkt.
|
||
- ✅ **Getestet:** 328 Tests grün (10 neue), `flutter analyze` ohne Befund.
|
||
|
||
### ✨ UI-Politur: Kontrast, Abstände, Typografie, Bewegung (2026-08-21)
|
||
|
||
Kein neues Design — dasselbe Melo in sauber. Schwarz/Rot, die vier Tabs und
|
||
Lieder/Kategorie bleiben unverändert.
|
||
|
||
- 🔍 **Behoben: blasse Schrift war nicht mehr lesbar.** An 17 Stellen stand
|
||
Text in `white38`. Nachgerechnet sind das **3,4:1** Kontrast — die
|
||
Barrierefreiheits-Grenze liegt bei **4,5:1**. Betroffen waren unter anderem
|
||
Metadaten, Equalizer und Wiedergabelisten. Alle Textfarben laufen jetzt über
|
||
drei benannte Stufen, und ein Test **rechnet die Kontraste bei jedem Lauf
|
||
nach** (WCAG 2.1) — behauptet wird nichts mehr.
|
||
| Stufe | Wofür | Kontrast |
|
||
|---|---|---|
|
||
| `text1` | Titel | 15,9:1 |
|
||
| `text2` | Künstler, Untertitel | 8,8:1 |
|
||
| `text3` | Anzahl, Zeit, Hinweis | 4,9:1 |
|
||
- 👆 **Behoben: die Reiter waren zu klein zum Treffen.** *Lieder · Kategorie ·
|
||
Künstler* waren nur ~38 dp hoch — Android verlangt **48 dp**, sonst tippt
|
||
man im Gehen daneben. Jetzt volle 48 dp, mit spürbarer Rückmeldung beim
|
||
Antippen (vorher gab es keine) und weichem Übergang statt hartem Sprung.
|
||
Vorlesehilfen bekommen die Auswahl jetzt als Zustand gemeldet, nicht nur
|
||
als weiße Farbe.
|
||
- 📏 **Abstände nach festem Raster.** Vorher standen überall Einzelwerte
|
||
(12, 9, 10, 18 …). Jetzt fünf benannte Stufen auf einem 8er-Raster —
|
||
deshalb wirken Listen und Karten ruhiger, ohne dass etwas verschoben wurde.
|
||
- 🔤 **Eine Schriftgrößen-Skala statt 52 Einzelangaben.** Sieben Stufen von
|
||
der Bildschirm-Überschrift bis zum Beiwerk, mit passender Zeilenhöhe. Kein
|
||
Text ist kleiner als 12.
|
||
- 🎛️ **Mini-Player überarbeitet.** Der Abspiel-Knopf ist jetzt rot gefüllt
|
||
und volle 48 dp groß — der wichtigste Knopf der Leiste lässt sich ohne
|
||
Hinsehen treffen. Die Leiste blendet sich ein und aus, statt aufzupoppen,
|
||
und ist durch eine Haarlinie vom Inhalt getrennt.
|
||
🐛 Nebenbei ein Layout-Fehler entschärft: die Zeile lag in einem `Expanded`
|
||
**um** eine feste Höhe herum — zwei widersprüchliche Angaben.
|
||
- 🖼️ **Karten und Cover bekommen einen Umriss** statt eines Schattens. Auf
|
||
Schwarz ist ein Schatten unsichtbar; eine Haarlinie trennt sauber.
|
||
- 🚫 **Emoji raus aus Bedienelementen.** In den Einstellungen stand
|
||
„🌐 Navidrome", „🌟 Favoriten-Sync" — jeweils direkt neben einem echten
|
||
Symbol. Emoji werden von Vorlesehilfen vorgelesen („Globus mit Meridianen")
|
||
und sehen auf jedem Gerät anders aus. Die Symbole bleiben, die Emoji sind weg.
|
||
- 🔧 **Details für Technikinteressierte:**
|
||
- Neu in `shared/theme.dart`: `MeloSpace`, `MeloRadius`, `MeloMotion`,
|
||
Textstufen `text1/2/3`, `border`, `hairline`, `minTouchTarget` sowie ein
|
||
vollständiges `textTheme` und Themes für Listen, Sheets, Snackbars,
|
||
Fortschritt und Trenner.
|
||
- Neu: `test/shared/theme_kontrast_test.dart` (rechnet WCAG-Kontraste,
|
||
Raster und Typo-Skala nach) und `test/shared/sub_tabs_test.dart`
|
||
(48 dp, Rückmeldung, Semantik, Übergang).
|
||
- Grundlage: Regeln aus **ui-ux-pro-max** (Priorität 1 Barrierefreiheit,
|
||
2 Touch, 6 Typografie/Farbe, 7 Bewegung), **ui-design/mobile-android**
|
||
(Material 3: 48 dp, Theme über `context`) und die Token-Disziplin aus
|
||
**Hue** (Primitives → benannte Rollen).
|
||
- ✅ **Getestet:** 318 Tests grün (23 neue), `flutter analyze` ohne Befund.
|
||
|
||
### 📋 Backlog-Datei angelegt (2026-08-21)
|
||
- Neu: `BACKLOG.md` — bewusst zurückgestellte Punkte an einer Stelle, damit
|
||
nichts stillschweigend liegen bleibt. Drin stehen aktuell der übersprungene
|
||
Widget-Test `song_detail_sheet_test.dart` (mit dem Stand der Eingrenzung und
|
||
dem nächsten Schritt) und die fehlende Wiederherstellung gelöschter Titel.
|
||
|
||
### 🗂️ Alben sind jetzt Kategorien — neue Bibliotheks-Reiter (2026-08-21)
|
||
|
||
- 🏷️ **Album = Kategorie.** Wer seine Sammlung über das **Album-Feld**
|
||
sortiert hat, findet sie ab sofort genau so unter *Kategorie* wieder — der
|
||
Album-Titel eines Liedes **ist** in Melo seine Kategorie. Nichts muss neu
|
||
gemacht werden.
|
||
🔧 Der Album-Titel steht dabei **vorn** in der Kategorienliste, weil die
|
||
erste Kategorie das Coverbild bestimmt (Einstellung „Gleiche Kategorie =
|
||
gleiches Coverbild"). Genres aus den Datei-Tags kommen weiterhin dazu,
|
||
aber dahinter.
|
||
🔁 **Bestehende Bibliotheken werden beim ersten Start automatisch
|
||
nachgerüstet** — du musst nicht erst neu scannen. Von Hand gepflegte
|
||
Kategorien bleiben dabei unangetastet.
|
||
- 📑 **Neue Reiter in „Meine Musik": Lieder · Kategorie · Künstler.** Der
|
||
Alben-Reiter ist verschwunden — er ist im Kategorie-Reiter aufgegangen.
|
||
„Songs" heißt jetzt „Lieder". Der Kategorie-Reiter zeigt jede Kategorie mit
|
||
Coverbild und Anzahl; Lieder ganz ohne Kategorie sammeln sich am Ende unter
|
||
*Ohne Kategorie*.
|
||
- ⬇️ **YouTube-Downloads: Kategorie beim Herunterladen wählen.** Im
|
||
YouTube-Bereich gibt es ein Feld **Kategorie (optional)** — es schlägt die
|
||
Kategorien deiner Bibliothek vor, nimmt aber auch eine neue entgegen. Leer
|
||
lassen = der Titel kommt ohne Kategorie in die Bibliothek.
|
||
🐛 **Warum das nötig ist:** YouTube-Dateien bringen ein Album-Tag mit, das
|
||
yt-dlp aus Kanal, Playlist oder Videotitel ableitet — Dinge wie
|
||
„Topic - Various Artists". Da das Album jetzt die Kategorie ist, hätte
|
||
**jeder Download eine neue Unsinns-Kategorie** erzeugt. Melo **verwirft**
|
||
dieses Album-Tag deshalb bewusst und nimmt stattdessen deine Angabe.
|
||
Beides wird als „von Hand gesetzt" markiert, damit der nächste Scan es
|
||
nicht wieder hereinholt.
|
||
- 🔧 **Details für Technikinteressierte:**
|
||
- Neu: `kategorienAusTags()` und `groupByCategory()` in
|
||
`library/categories.dart`, `library/category_list.dart`,
|
||
`downloads/download_einordnung.dart` (`ordneDownloadEin`,
|
||
`kategorieVorschlaege`).
|
||
- Beide Scans (Gerät + Ordner) tragen den Album-Titel als erste Kategorie
|
||
ein; `MeloDb.songByPath()` und `MeloDb.verwirfAlbum()` neu.
|
||
- Datenbank auf Version 9: einmalige Nachrüstung der Album-Kategorien.
|
||
- `CategoryService.alleNamen` liefert die Kategorienamen jetzt ohne
|
||
zusätzliche Abfrage — die Vorschlagsliste flackert dadurch nicht.
|
||
- Entfernt: `library/album_list.dart` sowie `groupByAlbum()` /
|
||
`albumArtistLabel()` — mit dem Alben-Reiter tot geworden. Das
|
||
**Album-Feld selbst bleibt** in den Metadaten erhalten.
|
||
- ✅ **Getestet:** 295 Tests grün (19 neue), `flutter analyze` ohne Befund.
|
||
|
||
### 📚 Hochgeladene Titel landen jetzt auch in Navidrome (2026-08-21)
|
||
|
||
- 🎵 **Was sich ändert:** Was du vom Handy hochlädst, taucht ab sofort **auch
|
||
in der Navidrome-Bibliothek** auf — also im Browser und in jeder anderen
|
||
Musik-App, die auf den Server zugreift. Vorher blieb es in der Melo-Cloud
|
||
liegen und war nur in Melo sichtbar.
|
||
🔧 **Wie:** Die Melo-Cloud hängt die hochgeladene Datei zusätzlich in
|
||
Navidromes Musikordner (als *Hardlink* — dieselbe Datei unter zwei Namen,
|
||
also **kein zusätzlicher Speicherplatz**) und stößt einen Scan an.
|
||
Navidrome hat den Titel binnen Sekunden. Löschst du ihn, verschwindet er
|
||
auch aus Navidrome — aber nur, wenn ihn kein anderes Konto mehr hat.
|
||
⚠️ **Zu wissen:** Navidrome hat **eine gemeinsame** Bibliothek. Was ein
|
||
Konto hochlädt, sehen dort alle Navidrome-Nutzer. In Melo bleibt die
|
||
Trennung pro Konto bestehen.
|
||
- 🩹 **Nebenbei repariert: Downloads vom Server gingen gar nicht.** Die 325
|
||
Titel der Melo-Cloud lagen nur noch im Navidrome-Ordner — der Ablageordner
|
||
der Cloud war leer. Jeder Download antwortete deshalb mit *„File missing"*.
|
||
Alle Dateien sind zurückverknüpft, Downloads gehen wieder.
|
||
- 🏷️ **Nebenbei repariert: falsche Dateiendungen.** Hochgeladene Dateien
|
||
wurden immer als `.mp3` abgelegt, auch M4A und FLAC; heruntergeladene
|
||
bekamen den Namen `Lied.m4a.m4a`. Jetzt zählt der echte Dateityp — auf dem
|
||
Server wie auf dem Handy (wichtig, damit Android den Titel richtig
|
||
einordnet).
|
||
- 🛑 **Neu: Sicherheitsbremse gegen Massenlöschung.** Der Bibliotheks-Scan
|
||
markiert jeden Titel als gelöscht, dessen Datei er nicht findet. Ist die
|
||
Speicherkarte einmal nicht eingehängt oder die Berechtigung entzogen,
|
||
betrifft das die halbe Sammlung — und ohne Bremse hätte der Abgleich sie
|
||
am Server und damit auf **allen** Geräten gelöscht. Melo hält jetzt an,
|
||
wenn mehr als 10 Titel **und** mehr als ein Drittel des Serverbestands auf
|
||
einmal verschwinden sollen, und sagt warum. Einzelne Löschungen laufen
|
||
unverändert durch.
|
||
- 🔧 **Details für Technikinteressierte:**
|
||
- `melo_cloud.py`: `verknuepfe_navidrome()` (Hardlink, Fallback Kopie),
|
||
`loese_navidrome()`, `rescan_navidrome()` (Subsonic `startScan.view` über
|
||
Navidromes `AuthProxyHeader` — **kein Passwort im Code**),
|
||
`registry_pfad()` als gemeinsame Dateisuche über alle Audio-Endungen.
|
||
- `handle_delete()` räumt die Datei ab, sobald kein Konto sie mehr aktiv
|
||
hat — der Registry-**Eintrag** bleibt aber stehen, sonst verlöre
|
||
`/list` den Grabstein und andere Geräte bekämen den Titel als Zombie
|
||
zurück.
|
||
- Neu: `scripts/melo_cloud_migriere_registry.py` (einmalige Rückverknüpfung)
|
||
und `scripts/test_melo_cloud_navidrome.py` (Durchlauf-Test).
|
||
- App: `MeloCloudService.herunterladen()` gibt die geschriebene Datei
|
||
zurück und leitet die Endung aus dem Inhaltstyp ab (`endungFuer`);
|
||
`loeschBremseGreift()` in `sync_service.dart`.
|
||
- ✅ **Getestet:** 276 Tests grün (9 neue) plus ein Durchlauf gegen den
|
||
echten Server: Upload → Registry + Navidrome (ein Hardlink) → Navidrome
|
||
liest ein → Löschen entfernt beides, Grabstein bleibt.
|
||
|
||
### 🔊 Lokale Lieder spielen wieder + Abgleich zwischen Handy und Server (2026-08-21)
|
||
|
||
- ▶️ **Behoben: Musik vom Handy war nicht abspielbar.** Titel, die auf dem
|
||
Gerät liegen, tauchten zwar in der Bibliothek auf, beim Antippen kam aber
|
||
nur *„Wiedergabe fehlgeschlagen: (0) Source error"* oder *„Loading
|
||
interrupted"*.
|
||
🐛 **Die Ursache:** Sobald ein Musikserver eingerichtet war, hat Melo
|
||
**jeden** Titel beim Server nachgefragt — auch die vom Handy. Als
|
||
„Song-Nummer" schickte die App dabei den Dateipfad (`file:///storage/…`).
|
||
Der Server kennt so etwas natürlich nicht und antwortete mit einer
|
||
Fehlermeldung. Diese Fehlermeldung reichte Melo dann als „Musikdatei" an
|
||
den Player weiter — daher der Fehler. Schlimmer noch: die Fehlermeldung
|
||
wurde als `.mp3` im Zwischenspeicher abgelegt, wodurch der Titel
|
||
**dauerhaft** kaputt blieb.
|
||
🔧 **Was jetzt anders ist:** Melo unterscheidet sauber zwischen Titeln vom
|
||
Gerät und Titeln vom Server. Für eine Datei auf dem Handy geht keine
|
||
einzige Anfrage mehr ins Netz — sie wird direkt abgespielt.
|
||
- ⚡ **Behoben: Wiedergabe startete gar nicht mehr.** Beim Antippen eines
|
||
Liedes lud Melo vorher die **gesamte** Warteschlange vom Server herunter,
|
||
bevor der erste Ton kam — bei hunderten Titeln also nie. Tippte man noch
|
||
einmal, brach der laufende Ladevorgang ab (*„Loading interrupted"*).
|
||
🔧 Jetzt startet der Titel sofort; das Zwischenspeichern für später läuft
|
||
im Hintergrund und nur für das Lied, das gerade läuft.
|
||
- 💾 **Behoben: der Offline-Zwischenspeicher wurde nie wiedergefunden.** Als
|
||
Ablage-Schlüssel diente die komplette Stream-Adresse — die enthält aber ein
|
||
Zufallsmerkmal, das Melo bei **jedem App-Start neu** erzeugt. Derselbe Titel
|
||
bekam also jedes Mal einen anderen Schlüssel: der Zwischenspeicher wuchs nur
|
||
noch und half nie. Jetzt zählt die Song-Nummer, und offline gespeicherte
|
||
Server-Titel laufen wirklich ohne Netz.
|
||
- 🧹 **Zwischenspeicher kann sich nicht mehr vergiften:** Es wird erst in eine
|
||
`.part`-Datei geschrieben und nur dann als Musik übernommen, wenn der
|
||
Server wirklich Audio geliefert hat. Abgebrochene Downloads hinterlassen
|
||
keine halben Dateien mehr.
|
||
|
||
- ☁️ **Neu: Abgleich zwischen Handy, Server und Web.** Unter
|
||
**Einstellungen → Geräte-Abgleich** hält Melo alles auf demselben Stand:
|
||
- ⬇️ Titel vom Server landen als richtige Datei auf dem Handy und sind
|
||
danach **offline** verfügbar.
|
||
- ⬆️ Eigene Dateien vom Handy gehen zum Server — auch von anderen Geräten
|
||
aus abrufbar.
|
||
- 🗑️ Löschungen wirken in beide Richtungen: was hier verschwindet, taucht
|
||
auf den anderen Geräten nicht wieder auf, und umgekehrt.
|
||
- ❤️ Favoriten und 🕐 Wiedergaben werden mitgemeldet.
|
||
- 🔄 Das passiert **automatisch** beim App-Start und beim Zurückkehren in
|
||
die App (höchstens alle 15 Minuten, damit es keinen Akku frisst). Der
|
||
Knopf für „jetzt sofort" ist trotzdem da.
|
||
⚠️ **Ehrlich gesagt:** Der Abgleich läuft über die **Melo-Cloud**
|
||
(`cloud.baka-net.de`), nicht über Navidrome. Grund: Navidrome bietet
|
||
schlicht keine Möglichkeit, Dateien hochzuladen — die Subsonic-Schnittstelle
|
||
kennt keinen Upload. Navidrome bleibt die Streaming-Bibliothek, die
|
||
Melo-Cloud ist der gemeinsame Speicher. Dafür ist eine Anmeldung beim
|
||
Baka-Konto nötig (Tab **Online → YouTube**). Einzelne Datei: max. 50 MB.
|
||
|
||
- 🏷️ **Behoben: Korrigierte Titelangaben gingen beim Scannen verloren.** Wer
|
||
Titel, Künstler oder Album von Hand richtiggestellt hatte, bekam beim
|
||
nächsten Bibliotheks-Scan wieder die falschen Angaben aus der Datei. Die
|
||
Markierung „von Hand bearbeitet" wurde nirgends gesetzt und nirgends
|
||
beachtet. Jetzt schon — in beiden Scans (Handy und Ordner).
|
||
|
||
- 🔧 **Details für Technikinteressierte:**
|
||
- `MeloAudioHandler.loadPlaylist` baut die Warteschlange ohne Netzzugriff;
|
||
neue reine Funktionen `navidromeIdOf`, `songIdOf`, `nutztServerCache`,
|
||
`quelleFuer`.
|
||
- Server-Titel tragen ihre Server-Nummer in `MediaItem.extras['navidromeId']`
|
||
statt sie aus der Abspiel-Adresse zu raten.
|
||
- `NavidromeService.ladeInCache()` ersetzt `streamAndCacheToLocal()`:
|
||
`.part`-Datei + Prüfung des Inhaltstyps (`istAudioAntwort`) +
|
||
stabiler Schlüssel (`cacheSchluessel`); der HTTP-Client wird geschlossen.
|
||
- Neu: `services/melo_cloud_service.dart`, `services/sync_service.dart`
|
||
mit der reinen Planungsfunktion `planeSync()`.
|
||
- Datenbank auf Version 8: neue Spalte `songs.cloud_id` verbindet einen
|
||
Titel auf dem Gerät mit seinem Gegenstück am Server.
|
||
- `database.g.dart` war veraltet und musste neu erzeugt werden — dadurch
|
||
ließ sich das Projekt vorher gar nicht übersetzen.
|
||
- ✅ **Getestet:** 267 Tests grün (78 neue), `flutter analyze` ohne Befund.
|
||
- ⚠️ **Offen:** Ein bestehender Widget-Test
|
||
(`song_detail_sheet_test.dart`) bleibt beim Öffnen des Detail-Fensters
|
||
hängen und blockierte den gesamten Testlauf. Er ist vorerst als
|
||
*übersprungen* markiert; sein Zweck wird jetzt von
|
||
`metadaten_uebernahme_test.dart` ohne Widgets abgedeckt.
|
||
|
||
### 🔎 Melo merkt selbst, wenn neue Musik da ist (2026-08-20)
|
||
- 📂 **Neue Dateien auf dem Handy:** Kommst du in die App zurück, sieht Melo
|
||
nach, ob sich der Musikbestand geändert hat — und liest neue Titel von
|
||
allein ein. Musik per Kabel überspielt oder anderswo heruntergeladen? Sie
|
||
ist einfach da, ohne dass du "Musik scannen" antippen musst.
|
||
🔧 **Wie sparsam das ist:** Melo vergleicht nur die **Anzahl** der Dateien
|
||
und prüft höchstens alle 5 Minuten. Der eigentliche Scan läuft nur, wenn
|
||
die Zahl abweicht — sonst passiert gar nichts.
|
||
⚠️ **Grenze, ehrlich gesagt:** Werden genauso viele Titel gelöscht wie
|
||
hinzukommen, bleibt die Zahl gleich und Melo merkt es nicht. Dafür gibt es
|
||
weiterhin den Knopf zum Scannen von Hand.
|
||
- 🌐 **Neues auf dem Musikserver:** Im Tab **Online → Server** erscheint ein
|
||
Hinweis, wenn auf Navidrome Alben dazugekommen sind ("3 neue Alben auf dem
|
||
Server"). Ein Tipp auf *Verstanden* und der Hinweis ist weg — dieselben
|
||
Alben melden sich nicht noch einmal.
|
||
🔧 Beim allerersten Mal meldet Melo bewusst **nichts**: sonst wäre deine
|
||
ganze Sammlung auf einmal "neu". Melo merkt sich still den Stand und
|
||
meldet ab dann nur noch, was wirklich dazukommt. Der Hinweis kostet keinen
|
||
zusätzlichen Serveraufruf — er nutzt die Alben, die ohnehin geladen werden.
|
||
- 🔧 **Details:**
|
||
- Neu: `library/auto_scan.dart` (6 Tests), `services/server_neuheiten.dart`
|
||
(5 Tests), `MeloDb.countSongs()` (1 Test),
|
||
`countAndroidMediaStoreSongs()`.
|
||
- `HomeShell` hört jetzt auf den App-Lebenszyklus (`resumed`).
|
||
- ✅ **Getestet:** 189 Tests grün (12 neue), `flutter analyze` ohne Befund.
|
||
|
||
### ⬇️ YouTube-Downloader mit Baka-Anmeldung (2026-08-20)
|
||
- 🎬 **Musik von YouTube holen:** Im Tab **Online → YouTube** eine Adresse
|
||
einfügen, auf *Herunterladen* tippen — fertig. Der Titel landet danach
|
||
automatisch in **Meine Musik**.
|
||
- 🔑 **Warum eine Anmeldung nötig ist:** Das Herunterladen erledigt der
|
||
Baka-Server (yt.baka-net.de), und der nimmt nur Anfragen von angemeldeten
|
||
Konten an. Deshalb gibt es im YouTube-Bereich einen Anmelde-Knopf für dein
|
||
**Baka-Konto**. Die Anmeldung wird **verschlüsselt auf dem Gerät**
|
||
gespeichert und gilt auch nach dem Neustart.
|
||
Läuft sie ab, sagt Melo das im Klartext ("Anmeldung abgelaufen — bitte neu
|
||
anmelden") statt eine Fehlernummer zu zeigen.
|
||
- 📂 **Wo die Musik landet:** In `Music/Melo` — dem **öffentlichen**
|
||
Musikordner. Das ist wichtig: Melo liest seine Bibliothek auf Android über
|
||
den MediaStore. Eine Datei, die nur in einem App-Ordner läge, wäre beim
|
||
nächsten Scan wieder verschwunden. Nebeneffekt: die Musik ist auch in
|
||
anderen Apps da.
|
||
- 🧹 **Keine Bruchstücke:** Der Download geht erst in einen Zwischenordner.
|
||
Erst wenn die Datei vollständig da ist, wandert sie in den Musikordner.
|
||
Bricht etwas ab, wird die halbe Datei gelöscht statt als kaputter Titel in
|
||
der Bibliothek zu landen.
|
||
- 🎤 **Künstler:** Steht der Titel als "Künstler - Lied" da, wird der
|
||
Künstler übernommen. Steht da nichts dergleichen, bleibt das Feld leer —
|
||
geraten wird nicht.
|
||
- 🔧 **Details:**
|
||
- Neu: `services/baka_auth.dart` (6 Tests), `services/yt_download_service.dart`
|
||
(8 Tests), `services/media_store.dart` (2 Tests) und die native Brücke
|
||
`MediaStoreBridge.kt` (MediaStore ab Android 10, Dateisystem + Scanner
|
||
davor).
|
||
- `WRITE_EXTERNAL_STORAGE` (nur bis Android 9) im Manifest ergänzt.
|
||
- Der Online-Tab hat jetzt die Unterreiter **YouTube · Server** (3 Tests);
|
||
`SubTabs` liegt dafür in `shared/sub_tabs.dart`.
|
||
- ⚠️ Der Anmelde-Server meldet Fehler mit Status 200 und Text im Rumpf —
|
||
der Code prüft deshalb den Inhalt, nicht nur den Statuscode.
|
||
- ✅ **Getestet:** 177 Tests grün (19 neue), `flutter analyze` ohne Befund,
|
||
Release-APK baut (22,8 MB).
|
||
⚠️ **Ehrlich dazugesagt:** Der Weg über den echten Proxy und das Schreiben
|
||
in den Musikordner sind **noch nicht auf dem Handy ausprobiert** — das
|
||
geht nur auf dem Gerät. Alles davor ist mit Tests abgedeckt.
|
||
|
||
### 🧭 Neue Tab-Struktur nach deinen Referenzbildern (2026-08-20)
|
||
- 🔀 **Untere Leiste wie auf deinem Bild:** Die Reihenfolge ist jetzt
|
||
**Meine Musik · Online · Suchen · Favoriten**. Der frühere Reiter
|
||
"Download" heißt jetzt **Online** (Musiknoten-Symbol) — dort kommt als
|
||
Nächstes der YouTube-Downloader dazu.
|
||
- 🗂️ **Unterreiter in "Meine Musik":** Über der Liste sitzen jetzt
|
||
**Songs · Künstler · Alben** als Pillen — genau wie in der Referenz. Der
|
||
aktive Reiter ist hell, die anderen sind nur Text.
|
||
Wichtig: Ein Unterreiter **wechselt nur den Inhalt** und öffnet keinen
|
||
neuen Bildschirm — Suchfeld und Schnellzugriffe bleiben stehen.
|
||
- 🧹 **Aufgeräumt:** Die Schnellzugriff-Kacheln "Künstler" und "Alben" sind
|
||
weg, weil sie jetzt Unterreiter sind. Übrig bleiben — wie in der Referenz —
|
||
**Favoriten · Wiedergabelisten · Zuletzt**.
|
||
- 🔧 **Details:** `MyMusicScreen` ist jetzt zustandsbehaftet (`_subTab`), neues
|
||
`_SubTabs`-Widget; die dadurch toten `ArtistsScreen`/`AlbumsScreen`-Hüllen
|
||
wurden entfernt (`ArtistListScreen`/`AlbumListScreen` bleiben und werden
|
||
direkt eingebettet).
|
||
- ✅ **Getestet:** 158 Tests grün (4 neue), `flutter analyze` ohne Befund.
|
||
|
||
### 🎼 Songtext, Warteschlange, Sperrbildschirm-Cover und gleiche Lautstärke (2026-08-20)
|
||
- 📝 **Automatischer Songtext:** Beim Scan wird der Songtext aus dem Tag der
|
||
Datei mitgelesen und in der Wiedergabe sofort angezeigt — **ohne Server und
|
||
ohne Internet**. Nur wenn die Datei keinen Text enthält, wird der
|
||
Navidrome-Server gefragt.
|
||
🐛 Nebenbei gefixt: Der Songtext-Knopf hat bisher die Datei-Adresse statt der
|
||
Song-ID weitergegeben, dadurch kam vom Server nie ein Text zurück.
|
||
- ➕ **Warteschlange ohne Nebenwirkungen:** Im ⋮-Menü einer Songzeile gibt es
|
||
jetzt **"Als Nächstes spielen"** und **"Zur Warteschlange hinzufügen"** —
|
||
beides ändert **nichts** an Favoriten oder Wiedergabelisten und
|
||
unterbricht die laufende Wiedergabe nicht. Umgekehrt entfernt das
|
||
✕ in der Warteschlange den Titel weiterhin nur dort — er bleibt Favorit
|
||
und bleibt in jeder Wiedergabeliste.
|
||
- 🖼️ **Sperrbildschirm zeigt dasselbe Bild wie die App:** Läuft ein Titel,
|
||
bekommt der Sperrbildschirm jetzt das **Kategorie-Cover** (sofern die
|
||
Einstellung "Gleiche Kategorie = gleiches Coverbild" an ist) statt eines
|
||
abweichenden Bildes. Auch Wiedergabelisten zeigen jetzt dieses Cover.
|
||
- 🔉 **Gleiche Lautstärke (ReplayGain):** Neuer Schalter unter *Einstellungen →
|
||
Ton* (standardmäßig an). Melo liest den ReplayGain-Tag der Datei und
|
||
**senkt laute Titel ab**, damit alles gleich laut wirkt.
|
||
⚠️ **Ehrlich dazugesagt:** Verstärken kann ein Player nicht über 100 %
|
||
hinaus — angeglichen wird deshalb immer nach unten. Und es funktioniert
|
||
nur bei Dateien, die den Tag mitbringen (typisch FLAC/OGG und mit
|
||
ReplayGain versehene MP3s). Dateien ohne Tag bleiben unverändert.
|
||
- 🔧 **Details:**
|
||
- DB-Schema 6: neue Spalten `lyrics` und `gain_db`.
|
||
- Neu: `player/replay_gain.dart` (7 Tests), `playNextIndex` +
|
||
`addToQueue`/`playNext` im Audio-Handler (3 Tests),
|
||
Cover-Vorgabe in `songToMediaItem` (3 Tests).
|
||
- ✅ **Getestet:** 154 Tests grün, `flutter analyze` ohne Befund.
|
||
|
||
### 🎚️ Equalizer, Dolby Atmos und automatische Wiedergabe (2026-08-20)
|
||
- ✅ **Was:** Die Einstellungen haben einen neuen Bereich **Ton** mit
|
||
Equalizer, Dolby Atmos und der automatischen Wiedergabe bei Kopfhörern.
|
||
- 🎛️ **Equalizer (echt, nicht nachgebaut):** Neuer Bildschirm mit den
|
||
Klangprofilen deines Geräts (Normal, Rock, Pop …), den Frequenzbändern als
|
||
senkrechte Regler mit Beschriftung (60Hz … 14.0kHz) und den beiden
|
||
Drehreglern **Bass** und **Immersives Audio** — wie auf deinem Bild. Zum
|
||
Regeln senkrecht über den Drehregler wischen.
|
||
Alle Werte werden gespeichert und nach dem Neustart wiederhergestellt.
|
||
- 🔊 **Wie das technisch geht:** Neue native Android-Brücke
|
||
(`AudioEffectsBridge.kt`) auf `android.media.audiofx` — Equalizer,
|
||
BassBoost und Virtualizer hängen an der Audio-Session des Players. Da
|
||
just_audio die Session-ID erst beim Abspielen meldet, verbindet sich die
|
||
App bei jedem Wechsel automatisch neu. Bietet ein Gerät einen Effekt nicht
|
||
an, wird er ausgegraut statt die App abstürzen zu lassen.
|
||
- 🎬 **Dolby Atmos:** Öffnet die **Klangeffekte des Systems** — auf deinem
|
||
POCO ist das die Dolby-Atmos-Seite. Eine App kann Dolby Atmos nicht selbst
|
||
steuern; der System-Weg ist der einzige, der wirklich funktioniert. Bietet
|
||
ein Gerät die Seite nicht an, sagt Melo das.
|
||
- 🎧 **Automatische Wiedergabe:** Neuer Schalter — sobald Kopfhörer verbunden
|
||
werden (Klinke **oder Bluetooth**), spielt Melo weiter. Eine bereits
|
||
laufende Wiedergabe wird nie unterbrochen, und ohne Warteschlange passiert
|
||
nichts.
|
||
- 🔧 **Details:**
|
||
- Neu: `player/audio_effects.dart` (6 Tests, u. a. Grenzwerte und
|
||
Wiederherstellen), `player/headphone_autoplay.dart` (6 Tests),
|
||
`settings/equalizer_screen.dart` inkl. selbst gezeichnetem Drehregler.
|
||
- `MODIFY_AUDIO_SETTINGS` im Manifest ergänzt (nötig für die Effekte).
|
||
- `MainActivity.kt` registriert die Brücke und gibt die Effekte beim
|
||
Beenden wieder frei.
|
||
- ✅ **Getestet:** 141 Tests grün, `flutter analyze` ohne Befund.
|
||
|
||
### 🏷️ Kategorien, Metadaten-Ansicht und Expertenmodus (2026-08-20)
|
||
- ✅ **Was:** Jeder Song kann jetzt **mehreren Kategorien** angehören. Sie
|
||
stehen in der Songzeile hinter dem Künstler ("Neoni | Trap cool · Chill") —
|
||
genau wie in deinem Entwurf.
|
||
- 📥 **Woher sie kommen:** Beim Scan aus dem **Genre-Tag** der Datei. Mehrere
|
||
Werte in einem Tag werden automatisch getrennt (`;` `,` `|` `/`), doppelte
|
||
fallen weg. Über **⋮ → Metadaten → Bearbeiten** kannst du Kategorien selbst
|
||
hinzufügen oder entfernen; bereits vergebene Kategorien werden als
|
||
Vorschläge angeboten.
|
||
- 🔒 **Von Hand schlägt Automatik:** Sobald du die Kategorien eines Songs
|
||
selbst änderst, überschreibt ein späterer Scan sie **nicht** mehr.
|
||
- 🖼️ **Gleiche Kategorie = gleiches Coverbild:** Neue Einstellung unter
|
||
*Einstellungen → Darstellung* (standardmäßig **an**, jederzeit abschaltbar).
|
||
Ist sie an, zeigen alle Songs einer Kategorie das Bild der **ersten**
|
||
Kategorie; hat die Kategorie kein Bild, bleibt das eigene Cover. Im
|
||
Metadaten-Fenster ist die bildgebende Kategorie mit einem Bild-Symbol
|
||
markiert.
|
||
- 🔬 **Expertenmodus:** Im Metadaten-Fenster ausklappbar — Titel, Künstler,
|
||
Album, Dauer, Wiedergaben, Hinzugefügt-Datum, Herkunft der Kategorien,
|
||
Format, Dateigröße und Pfad.
|
||
- 🔧 **Details:**
|
||
- DB-Schema 4: neue Tabelle `song_categories` (Song ↔ Kategorie mit
|
||
Reihenfolge) und Spalte `categories_edited`. Bestehende Bibliotheken
|
||
werden automatisch migriert.
|
||
- Neu: `library/categories.dart` (reine Logik: Tag zerlegen, Cover je
|
||
Kategorie ermitteln — 12 Tests), `library/category_service.dart`
|
||
(hält Kategorien + Cover-Zuordnung einmal zentral, 3 Tests),
|
||
`library/song_detail_sheet.dart`, `settings/app_settings.dart`.
|
||
- Beide Scanner (Android-MediaStore und Ordner-Scan) schreiben die
|
||
Kategorien mit.
|
||
- Das Drei-Punkte-Menü der Songzeile ersetzt den bisherigen
|
||
Playlist-Knopf und enthält "Metadaten" und "Zu Wiedergabeliste
|
||
hinzufügen".
|
||
- ✅ **Getestet:** 129 Tests grün, `flutter analyze` ohne Befund.
|
||
|
||
### 🎨 Neue Melo-Oberfläche: 4 Tabs + Sortierung (2026-08-20)
|
||
- ✅ **Was:** Die App hat jetzt die von dir gewünschte Struktur mit
|
||
**4 Tabs: Meine Musik · Suche · Favoriten · Download**. "Meine Musik" ist
|
||
der neue Startbildschirm — **ohne Topbar**, wie du es wolltest.
|
||
- 🎵 **Meine Musik:** Oben eine Kopfzeile mit Einstellungs-Icon (links),
|
||
Suchfeld (Mitte) und ?-Icon für die Musikerkennung (rechts, kommt später).
|
||
Darunter Schnellzugriff-Karten (Favoriten · Wiedergabelisten · Zuletzt ·
|
||
Künstler · Alben), dann **Shuffle-Wiedergabe + Sortieren**, dann die
|
||
komplette Liederliste.
|
||
- ↕️ **Sortieren (neu!):** Über das Symbol rechts neben "Shuffle-Wiedergabe"
|
||
kannst du wählen zwischen **Zuletzt hinzugefügt**, **Name (A–Z–#)** und
|
||
**Wie oft abgespielt** — jeweils auf- oder absteigend. Die Wahl wird
|
||
gespeichert und überlebt einen Neustart. Bei "Name" stehen Buchstaben
|
||
vorne und Ziffern/Sonderzeichen hinten unter "#"; Umlaute sortieren
|
||
richtig ein (Ärger steht bei A, nicht hinter Z).
|
||
- ❤️ **Favoriten-Tab:** eigener Tab mit Shuffle-Wiedergabe und **genau
|
||
derselben Sortierung** — mit eigener, getrennt gespeicherter Einstellung.
|
||
- ⬇️ **Download-Tab:** durchsucht den verbundenen Navidrome-Server
|
||
(Alben/Künstler); abgespielte Titel werden weiterhin automatisch lokal
|
||
zwischengespeichert.
|
||
- 🔢 **"Wie oft abgespielt" zählt jetzt wirklich:** Neue Spalte `playCount`
|
||
in der Datenbank (Schema 3, bestehende Bibliotheken werden automatisch
|
||
migriert). Gezählt wird beim Start eines Titels — nicht sekündlich,
|
||
solange er läuft.
|
||
- 🎨 **Farben:** Schwarz auf **#0B0B10** und Melo-Rot **#c0392b** (vorher ein
|
||
helleres Rot).
|
||
- 🔧 **Details:**
|
||
- Neu: `library/song_sort.dart` (reine Sortier-Logik, 11 Tests),
|
||
`shared/sort_store.dart` (Speichern der Wahl, 4 Tests),
|
||
`shared/sortable_song_list.dart` (Shuffle + Sortier-Menü),
|
||
`library/my_music_screen.dart`, `library/favorites_screen.dart`,
|
||
`downloads/downloads_screen.dart`.
|
||
- Der alte `library_screen.dart` (Tabs Alle/Künstler/Alben/Server) ist
|
||
entfallen — seine Inhalte leben jetzt in "Meine Musik" (Alle),
|
||
als eigene Bildschirme (Künstler/Alben) und im Download-Tab (Server).
|
||
- **Musik hinzufügen** und **Erneut scannen** saßen in der entfernten
|
||
Topbar und stehen jetzt in den **Einstellungen → Bibliothek**
|
||
(zusätzlich weiterhin im leeren Zustand von "Meine Musik").
|
||
- Der Mini-Player ist jetzt auf allen Tabs sichtbar (vorher war der
|
||
Player ein eigener Tab).
|
||
- 🐛 **Nebenbei gefixt:** Das Sortier-Menü ist scrollbar — auf niedrigen
|
||
Bildschirmen bzw. im Querformat war der "Übernehmen"-Knopf sonst nicht
|
||
erreichbar. Schnellzugriff-Karten liefen um 2 Pixel über.
|
||
- ✅ **Getestet:** 107 Tests grün, `flutter analyze` ohne Befund.
|
||
|
||
### 🔎 Login-Dialog zeigt jetzt die echte Server-Fehlermeldung (2026-08-20)
|
||
- ✅ **Was:** Schlägt der Navidrome-Login fehl, zeigt der Dialog jetzt die
|
||
Original-Meldung des Servers (z. B. „Wrong username or password") statt
|
||
nur „Login fehlgeschlagen". So ist sofort klar, ob das Passwort falsch ist
|
||
oder ein Netzwerkproblem vorliegt.
|
||
- 🔧 **Details:**
|
||
- `NavidromeService.letzterLoginFehler` hält die Server-Meldung des letzten
|
||
abgelehnten Logins fest (wird bei jedem Ping zurückgesetzt).
|
||
- Das Fehler-Log enthält jetzt die Passwort-**Länge** (`pwLen=…`, nie das
|
||
Passwort selbst) — ein Tippfehler wird so im Log sofort sichtbar
|
||
(`Melo…!` hat 11 Zeichen).
|
||
- 🐛 **Hintergrund (tiefe Debug-Runde):** Server-seitig ist alles nachweislich
|
||
korrekt — Subsonic-API (`/rest/*`) läuft trotz SSO-Umbau ohne Forward-Auth,
|
||
DB-Passwort für „Baka" stimmt, und die exakte App-Token-Logik (Base64-Salt +
|
||
md5) wurde 8/8-mal erfolgreich gegen den Live-Server reproduziert. Die
|
||
Ablehnungen kommen von einem falschen Passwort-Wert auf dem Gerät; die neue
|
||
Fehlermeldung macht genau das künftig direkt sichtbar.
|
||
|
||
### 🔎 Login-Diagnose: Passwort-Sichtbarkeit + Trim (2026-08-20)
|
||
- 🐛 **„Login fehlgeschlagen" trotz korrekter Zugangsdaten:** Systematische
|
||
Analyse (App-Code, App-Logs, Caddy/Navidrome-Logs, 1:1-Nachbau des
|
||
App-Requests inkl. Salt/Token) hat bewiesen: **App-Code, Server, User „Baka"
|
||
und Passwort sind korrekt** — der Fehler lag im auf dem Gerät verwendeten
|
||
Credential-Wert (der ältere Build mit dem Ping-Fehlalarm persistierte
|
||
ungültige Zugangsdaten; verdeckte Tippfehler im Passwortfeld blieben
|
||
unsichtbar).
|
||
- 🔧 **Passwort-Anzeigen-Umschalter** (Auge-Icon) im Navidrome-Login — Tippfehler
|
||
werden sichtbar.
|
||
- 🔧 **URL + Passwort werden getrimmt** (randständige Leerzeichen aus Autofill /
|
||
Tastatur entfernt).
|
||
- 🔧 **Default-User im Login ist jetzt „Baka"** (vorher „Dustin") — verhindert
|
||
versehentlichen Login mit falschem User.
|
||
- ℹ️ Ein erfolgreicher Login überschreibt die alten (ungültigen) gespeicherten
|
||
Zugangsdaten — der Ping-Fix aus dieser Version stellt sicher, dass künftig
|
||
nur noch gültige Credentials gespeichert werden.
|
||
|
||
### 🔒 Datenschutz: Log-Bereinigung vor Server-Upload (2026-08-20)
|
||
- ✅ **Was:** Diagnose-Logs werden jetzt zentral bereinigt, bevor sie an
|
||
`logs.baka-net.de` gehen. Der lokale `debugPrint` bleibt vollständig.
|
||
- 🔧 **Details:**
|
||
- Freitext-Scrubber für `message` + `stackTrace`: maskiert sensible
|
||
`key=value`-Fragmente (`user=`, `pw=`, `password=`, `token=`, `secret=`,
|
||
`url=`), Datei-Pfade (`<path>`), nackte URLs (`<url>`), `Bearer`-Token,
|
||
JWTs (`<jwt>`) und lange Hex-IDs (`<hex>`).
|
||
- `stackTrace` wird auf max. 8 Zeilen gekürzt.
|
||
- `deviceModel` sendet nur noch die grobe Plattform (`android`/`ios`) statt
|
||
Hersteller+Modell (war ein Geräte-Fingerprint) — `device_info_plus` im
|
||
Logger entfernt.
|
||
- 🐛 **Fix (Quelle):** Der Navidrome-Login in `settings_screen` loggte
|
||
Benutzername + Server-URL im Klartext (`Login: url=… user=…`). Diese
|
||
Aufrufe senden jetzt nur noch den neutralen Status inkl. `pwLeer`-Flag.
|
||
- 🧪 **Tests:** neue Suite `test/logger_service_test.dart` (9 Tests) — 79/79 grün,
|
||
`flutter analyze` ohne Issues.
|
||
- ℹ️ **Offen:** Opt-in/Einwilligung für den Diagnose-Versand bleibt ein
|
||
separater Folgeschritt (braucht UI).
|
||
|
||
### 🐛 Server-Bibliothek lädt + Tab abgeschnitten (2026-08-20)
|
||
- 🐛 **Server-Bibliothek lud nicht ("Erneut versuchen"):** Ursache war, dass
|
||
der Code das Subsonic-`status`-Feld ignorierte. Navidrome liefert auch bei
|
||
falschem Passwort **HTTP 200** mit `status:"failed"` — `ping()` meldete
|
||
dadurch fälschlich „Login ok", und `getAlben`/`getArtists` behandelten die
|
||
Fehlerantwort still als „leer".
|
||
- 🔧 `ping()` prüft jetzt den Body (`status`) — kein Fehlalarm mehr beim Login.
|
||
- 🔧 `getAlben`/`getArtists` werfen bei `status:"failed"` eine
|
||
`NavidromeException` mit Server-Meldung statt still `[]` zurückzugeben.
|
||
- 🔧 Der Server-Tab zeigt die echte Server-Fehlermeldung (z. B. „Wrong
|
||
username or password") statt nur „Keine Alben geladen".
|
||
- 🔧 Album-Abruf nutzt jetzt den ID3-Endpoint `getAlbumList2` (konsistent zu
|
||
`getArtists`) — der alte Folder-Endpoint `getAlbumList` liefert bei
|
||
tag-organisierten Libraries leer.
|
||
- 🐛 **Tab „🌐 Server" war abgeschnitten** (nur „Serve" sichtbar): Die 4 festen
|
||
Tabs waren zu eng. `labelPadding` verkleinert (engere Abstände) —
|
||
Schriftgröße unverändert.
|
||
- 🧪 Neue Tests: `test/navidrome_parse_test.dart` (5). 84/84 grün, analyze sauber.
|
||
|
||
### 🔧 Log-Upload System - Fixes (2026-08-19)
|
||
- ✅ **ERROR-Level Logging**: Fehler werden SOFORT zum Server hochgeladen (async/await Fixed)
|
||
- ✅ **Navidrome-Service Error Logging**: Alle API-Fehler (ping, getAlben, getSongs, getFavorites, getArtists, getArtistSongs, getLyrics, scrobble, getBookmarks, getPlaylists, getPlaylistSongs) werden jetzt mit `logger.error()` zum Server geloggt (statt nur debugPrint)
|
||
- ✅ **Login-Fehler Detail-Logging**: Fehler enthalten URL, User, Exception-Typ und StackTrace
|
||
- ✅ **HTTP-Error bei Stream**: Stream-Fehler mit HTTP-Statuscode werden auch geloggt
|
||
- ✅ **Payload-Format**: Logs senden als `{"logs": [...]}` Array zum Server
|
||
|
||
### 🎉 RELEASE BUILD v3: Phase 2 + Login + Auto-Bugreport System!
|
||
**Build Date:** 2026-08-19 21:30
|
||
**APK (Release/Universal):** `app-release.apk` (22.3 MB) — **Mit Auto-Logger + Login-Improvements!**
|
||
**APK (ARM64-Specific):** `app-arm64-v8a-release.apk` (21 MB) — **Optimal für POCO X7 Pro**
|
||
**Tests:** 70/70 ✅
|
||
**Build Status:** ✅ SUCCESS
|
||
|
||
**Neue Features in dieser Build:**
|
||
- ✨ Login-Verbesserungen: Auto-URL + User-Buttons + Gast-Modus
|
||
- 📊 Auto-Bugreport System: Logger sendet Fehler sofort + andere Logs gesammelt zum Server
|
||
- Device-Info (Model + OS) + Timestamp + Stack-Traces
|
||
- Integration in Navidrome-Service für Login-Fehler-Diagnose
|
||
- 📝 Alle Phase-2-Features (Sync, Caching, Player, Controls)
|
||
- 🔒 Secure Credential-Speicherung
|
||
- 🎵 Enhanced MiniPlayer mit Skip-Buttons
|
||
|
||
### Phase 2 (Part 1-8 Completed — MILESTONE!)
|
||
- 🗄️ **Auto-Caching**: Lieder werden automatisch beim Streamen lokal gespeichert!
|
||
- Cache-First-Logik: Existierende Dateien lokal spielen
|
||
- Fallback: Vom Server streamen wenn kein Cache
|
||
- Cache-Speicher-Status in Settings (MB/KB/B) mit Clear-Button
|
||
- 🗄️ **CacheManager**: MD5-Hash-basierte Cache-Verwaltung (getCacheSize, clearCache)
|
||
- 📴 **Offline-Mode**: Toggle in Settings aktiviert Offline-Betrieb (nur gecachte Lieder spielen)
|
||
- 🎤 **Artist-Browse**: Toggle in Navidrome-Tab zwischen Albums ↔ Künstler, Tap lädt alle Songs des Künstlers
|
||
- 🌟 **Favoriten-Sync**: Button in Settings lädt Server-Favoriten und importiert sie lokal
|
||
- 📊 **History-Sync**: Wiedergabe-Position vom Server laden + alle 5s zum Server senden (Subsonic-Bookmarks)
|
||
- 📋 **Playlisten-Sync**: Button in Settings lädt alle Server-Playlisten (mit 🌐 Präfix zur Unterscheidung)
|
||
- 🔒 **Lock-Screen Controls**: Notification mit Play/Pause/Skip-Buttons auf Android Lock Screen
|
||
- 🎵 **Enhanced MiniPlayer**: Now-Playing Widget auf allen Tabs mit Skip-Buttons + Progress-Bar
|
||
- Infrastructure für Multi-Device Sync vorbereitet
|
||
|
||
### Added
|
||
- 🌐 **Musikserver-Tab** in Bibliothek: Zeige Alben vom Navidrome-Server, tippe um Album abzuspielen
|
||
- 📝 **Lyrics-Anzeige**: Lyrics-Button im Now-Playing Screen, Bottom-Sheet mit Song-Lyrics vom Server
|
||
- 🔀 **Shuffle & Repeat Modi**: Shuffle-Button (aktiv = rot), Repeat-Cycle (Off → All → One), beide im Player
|
||
- 🌐 Navidrome-Integration (Musikserver-Verbindung): Settings-Tab bietet Login/Logout für Subsonic-API-kompatible Server
|
||
- Navidrome-Service mit sichere Credential-Speicherung (Secure Storage + SharedPreferences)
|
||
- Server-Album-Browser: Lädt Alben vom Server, zeigt Songcount, tippe um Album in Queue zu laden
|
||
- Server-APIs erweitert: getArtists(), getArtistSongs(), setFavorite(), getFavorites(), getLyrics() (Phase 2 vorbereitet)
|
||
- Dependencies für Navidrome hinzugefügt: http, crypto, shared_preferences, flutter_secure_storage
|
||
|
||
### Known Limitations (Phase 2)
|
||
- Server-Favoriten-Sync: APIs vorhanden, UI-Integration in Phase 2
|
||
- Artist-Browse: APIs vorhanden, UI in Phase 2
|
||
- Server-Caching: Musik wird nicht lokal für Offline gecacht (Phase 2)
|
||
- Lyrics-Sync: Keine Timed-Synchronisation (Phase 2+)
|
||
|
||
## [1.0.0-alpha]
|
||
|
||
### Added
|
||
- Playlisten-Tab: Favoriten-Kurzeinstieg oben, Liste aller Playlisten mit Songanzahl,
|
||
Erstellen-Dialog (FAB), Löschen mit Bestätigung
|
||
- 🎵➕ Songs per Bottom-Sheet zu Playlisten hinzufügen (neuer Button in der Songliste,
|
||
neben dem Favoriten-Herz)
|
||
- Playlist-Detailansicht: Songs per Drag & Drop umsortieren, einzeln entfernen,
|
||
Antippen spielt die Playlist ab dieser Stelle
|
||
- Datenbank: Playlisten, Favoriten und Wiedergabe-Historie Tabellen (Drift, Schema v2)
|
||
- PlaylistService für Playlisten- und Favoriten-Verwaltung
|
||
- ❤️ Favoriten-Herz in der Songliste (ausgefüllt/leer)
|
||
- ❤️ Favoriten-Herz auch im Now-Playing-Screen (aktueller Song)
|
||
- Bibliothek: Künstler- und Alben-Tabs neben "Alle" — Songs werden clientseitig
|
||
aus der bestehenden Songliste gruppiert (alphabetisch sortiert, fehlender
|
||
Künstler/Album → "Unbekannt" / "Unbekanntes Album"); Antippen öffnet die
|
||
Songliste des jeweiligen Künstlers/Albums, Alben zeigen zusätzlich das Cover
|
||
- Warteschlangen-Ansicht (Queue-Button in der Now-Playing-AppBar): zeigt die
|
||
aktuelle Wiedergabeliste, hebt den laufenden Titel hervor, per Antippen
|
||
direkt zu einem Titel springen, Titel entfernen oder per Drag & Drop
|
||
umsortieren — ohne Änderungen am Audio-Handler (Queue wird clientseitig
|
||
neu berechnet und neu geladen)
|
||
- Wiedergabeposition wird alle 5 Sekunden gespeichert und beim erneuten
|
||
Abspielen eines Songs automatisch fortgesetzt (kein Resume bei den letzten
|
||
3 Sekunden eines Songs, um ein sofortiges Ende zu vermeiden)
|
||
- Settings-Tab: Bibliotheks-Statistik (Song-Anzahl + Gesamtspieldauer),
|
||
Musik-Berechtigung mit Link in die Systemeinstellungen, kurzer
|
||
"Über Melo"-Abschnitt — bewusst ohne Platzhalter für Profil/Cloud-Sync/
|
||
Geräte-Verwaltung, da es dafür noch kein Account-/Cloud-System gibt (Phase 2)
|
||
|
||
**Damit ist das komplette 5-Tab-MVP fertig: Player / Bibliothek / Playlisten /
|
||
Suche / Settings — inklusive Playlisten, Favoriten, Warteschlangen-Verwaltung,
|
||
Künstler-/Alben-Browsing und automatischem Fortsetzen der Wiedergabeposition.**
|
||
|
||
### Changed
|
||
- Now-Playing-Screen läuft jetzt als eigener Tab statt als gepushter Screen (kein Schließen-Button mehr in der AppBar)
|
||
- MediaItem trägt jetzt die Song-UUID mit (`extras['songId']`), nicht mehr nur die Datei-URI
|
||
- Finales 5-Tab-Layout: Player / Bibliothek / Playlisten / Suche / Settings (Playlisten und Settings vorerst als Platzhalter)
|
||
- "Zuletzt hinzugefügt" aus der alten Startseite ist jetzt Teil der Bibliothek (horizontale Leiste oben)
|
||
- MiniPlayer wird auf dem Player-Tab ausgeblendet (dort läuft schon die volle Ansicht)
|
||
|
||
### Fixed
|
||
- 🐛 Der APK-Build funktioniert jetzt überhaupt. Drei Dinge waren nötig:
|
||
`compileSdk = 37` und `kotlin.jvm.target.validation.mode=warning` existierten
|
||
bisher nur lokal auf dem Server und fehlten im Repo — ohne sie bricht der Build
|
||
ab, weil `permission_handler` SDK 37 verlangt. Zusätzlich hebt ein Gradle-
|
||
Workaround jetzt Plugin-Module mit zu altem `compileSdk` auf 36 an:
|
||
`on_audio_query_android` kompiliert gegen SDK 33, seine AndroidX-Abhängigkeiten
|
||
verlangen aber mindestens 34 (16 Metadaten-Konflikte).
|
||
|
||
### Removed
|
||
- Alte Startseite (`home_screen.dart`) entfernt — Funktionalität in die Bibliothek verschoben
|
||
|
||
### Known Issues
|
||
- Genre-Browsing fehlt noch: die `Songs`-Tabelle hat keine Genre-Spalte und
|
||
keiner der Scanner (scan_service.dart, android_scan.dart) liest Genre-
|
||
Metadaten aus den Dateien aus. Das ursprünglich geplante dritte Bibliotheks-
|
||
Tab "Genres" ist deshalb nicht umgesetzt — braucht eine Schema-Migration
|
||
plus Metadaten-Extraktion im Scanner (eigene Aufgabe, außerhalb dieses Tasks)
|