Files
encore/docs/TODO.md
T

108 lines
5.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Roadmap / TODO
Near-term work after the working MVP (connect + auto-connect, now-playing with
transport/volume/options, DataStore-persisted settings). Roughly ordered by
priority; not a commitment.
Status legend: `[ ]` todo · `[~]` in progress · `[x]` done
---
## [x] 1. Proper icons
Done. Replaced the placeholder unicode glyphs in `NowPlayingScreen.kt` with real
Material icons (`Icons.Filled.SkipPrevious/PlayArrow/Pause/SkipNext/VolumeUp`,
plus `Repeat`/`Shuffle` leading icons on the chips) from
`androidx.compose.material:material-icons-extended`.
- That artifact bundles thousands of vectors, so the **debug** APK grew ~7 MB
(expected — debug can't shrink). Enabled **R8 + resource shrinking** on the
`release` build type, which strips the unused icons: release APK is ~1.2 MB.
- Considered `material-icons-core` (too small — no media icons) and bundling
individual vector drawables (leaner but manual); the extended dep + R8 was the
best effort/quality trade.
## [ ] 2. Settings menu
A dedicated settings screen where the user can view every setting and reset it.
- Currently settings (host/port) are only editable by hitting **Disconnect** to
get back to the connect form. Add a real settings route.
- Include a **Reset** action that clears DataStore (add a `clear()` to
`SettingsRepository`).
- Will likely want simple navigation (Navigation-Compose, or a screen enum in
`PlayerViewModel`/`AppScreen`).
- Room to grow: password field, connection timeout, theme, keep-screen-on.
## [x] 3. Cast-style volume + OS media integration
Done — full MALP-style **OS integration**, not just in-app. Architecture:
- **`MpdConnectionManager`** (app-scoped, held by `MusicRemoteApplication`) now
owns the single `MpdClient`, so the connection survives Activity recreation and
runs while the service is up. `PlayerViewModel` is a thin delegate over it.
- **`PlaybackService`** — a `mediaPlayback` foreground service hosting a
`MediaSessionCompat`:
- **Cast-style volume**: `setPlaybackToRemote(VolumeProviderCompat)` (absolute,
0100). The OS routes hardware volume keys to the *server* volume
**system-wide, even when the app is backgrounded** (verified: 50→40 via
injected keys from the launcher), and shows the remote-volume UI. Replaced
the earlier in-app `onKeyDown` hack. Rapid presses accumulate via
`pendingVolume`.
- **Now-playing notification / QS / lock-screen** via a `MediaStyle`
notification bound to the session, with prev/play-pause/next actions
(`MediaButtonReceiver`) and metadata/position mirrored from the flows.
- Needs `POST_NOTIFICATIONS` (requested in `MainActivity`) +
`FOREGROUND_SERVICE[_MEDIA_PLAYBACK]`.
- In-app **`CastIndicator`** ("Controlling <host>") still shown above the slider.
Notes: verified on the FiiO via injected key events (a rotary volume knob may not
emit `VOLUME_UP/DOWN` — hardware-dependent). Album art in the notification/session
is pending item #5.
## [ ] 4. Library browse — albums
A screen to browse all albums on the server (artists can come later).
- MPD commands: `list album group albumartist` (or `list album`), and
`find album "<name>"` to fetch an album's tracks; add to the queue with
`add`/`findadd`. Extend `MpdCommands` + `MpdClient`.
- Grid or list of albums → tap to view/queue tracks.
## [ ] 5. Album / artist images
Pull artwork for the now-playing track and for the album browse grid.
- MPD serves art over the protocol via `albumart <uri> <offset>` and
`readpicture <uri> <offset>` (embedded art). **`MpdConnection` already handles
binary responses**, so the transport groundwork is done — add the commands,
loop over offsets to fetch the whole image, and decode.
- Needs an image loader + caching. Coil (`io.coil-kt`) is the standard Compose
choice; a custom `MpdArtFetcher` could feed it. Dependency → `deps.json` regen.
## [ ] 6. BUG: idle connection drops after a few minutes → kicked to connect page
After a few minutes idling, the app surfaces **"connection closed mid-response"**
and falls back to the connect screen. MALP does not do this.
- Error origin: `MpdConnection.readResponse()` hits EOF and throws
`MpdConnectionException("connection closed mid-response")`; the idle loop's
`catch (IOException)` calls `failAndClose()``MpdConnectionState.Error`
UI shows the connect form.
- Likely causes to investigate:
- **Android Doze / WiFi power-save** tearing down sockets when the screen is
off or the app is backgrounded (most likely on a portable DAP/phone).
- MPD's `connection_timeout` (default 60s) closing a connection it considers
idle — a parked `idle` should count as active, but the *command* connection
sits silent; a periodic `ping` keepalive may be needed.
- NAT/router idle-connection reaping (less likely on LAN).
- Fix direction: don't treat an idle-connection drop as a fatal error — instead
**auto-reconnect transparently** (re-open connections, re-issue `idle`, resync
state) and keep showing the player. Consider a keepalive ping and, for
backgrounded playback control, a foreground service / partial wakelock.
- PARTIALLY ADDRESSED by item #3: the `mediaPlayback` foreground service now
keeps the process/connection alive in the background, which should stop Doze /
wifi power-save from tearing the sockets down (the most likely cause). Still
worth verifying over a long idle, and adding transparent auto-reconnect +
keepalive ping as defense-in-depth (e.g. against MPD `connection_timeout`).