# 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. ## [x] 2. Settings menu Done. `SettingsScreen` (reached via a gear icon on the now-playing screen) shows the current server (host/port) with **Change server** (disconnect → connect form) and **Reset settings** (confirm dialog → clears DataStore + disconnects). - `SettingsRepository.clear()` wipes DataStore; `MpdConnectionManager.resetSettings()` clears + disconnects. - Navigation is lightweight state (`showSettings` in `MusicRemoteApp`, only over the player screen; a `LaunchedEffect` drops it when leaving the player) — no Navigation-Compose dependency yet. - Room to grow: password field, connection timeout, theme, keep-screen-on — and if screens multiply, revisit adopting Navigation-Compose. ## [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, 0–100). 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 ") still shown above the slider. - **Foreground key handling** (`VolumeKeyDispatcher`, delegated from `MainActivity.dispatchKeyEvent`): while focused, volume keys are consumed and drive the server silently — no system volume slider (the app's own slider is the feedback). Backgrounded, the `VolumeProvider` takes over (system UI is fine there). Gated by `MpdConnectionManager.isControllingVolume`; passes through to local volume when not connected. 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 ""` 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 ` and `readpicture ` (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`).